swift 2.23.3__py3-none-any.whl → 2.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- swift/__init__.py +29 -50
- swift/account/auditor.py +21 -118
- swift/account/backend.py +33 -28
- swift/account/reaper.py +37 -28
- swift/account/replicator.py +22 -0
- swift/account/server.py +60 -26
- swift/account/utils.py +28 -11
- swift-2.23.3.data/scripts/swift-account-audit → swift/cli/account_audit.py +23 -13
- swift-2.23.3.data/scripts/swift-config → swift/cli/config.py +2 -2
- swift/cli/container_deleter.py +5 -11
- swift-2.23.3.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +8 -7
- swift/cli/dispersion_report.py +10 -9
- swift-2.23.3.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +63 -21
- swift/cli/form_signature.py +3 -7
- swift-2.23.3.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +8 -2
- swift/cli/info.py +154 -14
- swift/cli/manage_shard_ranges.py +705 -37
- swift-2.23.3.data/scripts/swift-oldies → swift/cli/oldies.py +25 -14
- swift-2.23.3.data/scripts/swift-orphans → swift/cli/orphans.py +7 -3
- swift/cli/recon.py +196 -67
- swift-2.23.3.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +17 -20
- swift-2.23.3.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
- swift/cli/relinker.py +807 -126
- swift/cli/reload.py +135 -0
- swift/cli/ringbuilder.py +217 -20
- swift/cli/ringcomposer.py +0 -1
- swift/cli/shard-info.py +4 -3
- swift/common/base_storage_server.py +9 -20
- swift/common/bufferedhttp.py +48 -74
- swift/common/constraints.py +20 -15
- swift/common/container_sync_realms.py +9 -11
- swift/common/daemon.py +25 -8
- swift/common/db.py +195 -128
- swift/common/db_auditor.py +168 -0
- swift/common/db_replicator.py +95 -55
- swift/common/digest.py +141 -0
- swift/common/direct_client.py +144 -33
- swift/common/error_limiter.py +93 -0
- swift/common/exceptions.py +25 -1
- swift/common/header_key_dict.py +2 -9
- swift/common/http_protocol.py +373 -0
- swift/common/internal_client.py +129 -59
- swift/common/linkat.py +3 -4
- swift/common/manager.py +284 -67
- swift/common/memcached.py +390 -145
- swift/common/middleware/__init__.py +4 -0
- swift/common/middleware/account_quotas.py +211 -46
- swift/common/middleware/acl.py +3 -8
- swift/common/middleware/backend_ratelimit.py +230 -0
- swift/common/middleware/bulk.py +22 -34
- swift/common/middleware/catch_errors.py +1 -3
- swift/common/middleware/cname_lookup.py +6 -11
- swift/common/middleware/container_quotas.py +1 -1
- swift/common/middleware/container_sync.py +39 -17
- swift/common/middleware/copy.py +12 -0
- swift/common/middleware/crossdomain.py +22 -9
- swift/common/middleware/crypto/__init__.py +2 -1
- swift/common/middleware/crypto/crypto_utils.py +11 -15
- swift/common/middleware/crypto/decrypter.py +28 -11
- swift/common/middleware/crypto/encrypter.py +12 -17
- swift/common/middleware/crypto/keymaster.py +8 -15
- swift/common/middleware/crypto/kms_keymaster.py +2 -1
- swift/common/middleware/dlo.py +15 -11
- swift/common/middleware/domain_remap.py +5 -4
- swift/common/middleware/etag_quoter.py +128 -0
- swift/common/middleware/formpost.py +73 -70
- swift/common/middleware/gatekeeper.py +8 -1
- swift/common/middleware/keystoneauth.py +33 -3
- swift/common/middleware/list_endpoints.py +4 -4
- swift/common/middleware/listing_formats.py +85 -49
- swift/common/middleware/memcache.py +4 -95
- swift/common/middleware/name_check.py +3 -2
- swift/common/middleware/proxy_logging.py +160 -92
- swift/common/middleware/ratelimit.py +17 -10
- swift/common/middleware/read_only.py +6 -4
- swift/common/middleware/recon.py +59 -22
- swift/common/middleware/s3api/acl_handlers.py +25 -3
- swift/common/middleware/s3api/acl_utils.py +6 -1
- swift/common/middleware/s3api/controllers/__init__.py +6 -0
- swift/common/middleware/s3api/controllers/acl.py +3 -2
- swift/common/middleware/s3api/controllers/bucket.py +242 -137
- swift/common/middleware/s3api/controllers/logging.py +2 -2
- swift/common/middleware/s3api/controllers/multi_delete.py +43 -20
- swift/common/middleware/s3api/controllers/multi_upload.py +219 -133
- swift/common/middleware/s3api/controllers/obj.py +112 -8
- swift/common/middleware/s3api/controllers/object_lock.py +44 -0
- swift/common/middleware/s3api/controllers/s3_acl.py +2 -2
- swift/common/middleware/s3api/controllers/tagging.py +57 -0
- swift/common/middleware/s3api/controllers/versioning.py +36 -7
- swift/common/middleware/s3api/etree.py +22 -9
- swift/common/middleware/s3api/exception.py +0 -4
- swift/common/middleware/s3api/s3api.py +113 -41
- swift/common/middleware/s3api/s3request.py +384 -218
- swift/common/middleware/s3api/s3response.py +126 -23
- swift/common/middleware/s3api/s3token.py +16 -17
- swift/common/middleware/s3api/schema/delete.rng +1 -1
- swift/common/middleware/s3api/subresource.py +7 -10
- swift/common/middleware/s3api/utils.py +27 -10
- swift/common/middleware/slo.py +665 -358
- swift/common/middleware/staticweb.py +64 -37
- swift/common/middleware/symlink.py +51 -18
- swift/common/middleware/tempauth.py +76 -58
- swift/common/middleware/tempurl.py +191 -173
- swift/common/middleware/versioned_writes/__init__.py +51 -0
- swift/common/middleware/{versioned_writes.py → versioned_writes/legacy.py} +27 -26
- swift/common/middleware/versioned_writes/object_versioning.py +1482 -0
- swift/common/middleware/x_profile/exceptions.py +1 -4
- swift/common/middleware/x_profile/html_viewer.py +18 -19
- swift/common/middleware/x_profile/profile_model.py +1 -2
- swift/common/middleware/xprofile.py +10 -10
- swift-2.23.3.data/scripts/swift-container-server → swift/common/recon.py +13 -8
- swift/common/registry.py +147 -0
- swift/common/request_helpers.py +324 -57
- swift/common/ring/builder.py +67 -25
- swift/common/ring/composite_builder.py +1 -1
- swift/common/ring/ring.py +177 -51
- swift/common/ring/utils.py +1 -1
- swift/common/splice.py +10 -6
- swift/common/statsd_client.py +205 -0
- swift/common/storage_policy.py +49 -44
- swift/common/swob.py +86 -102
- swift/common/{utils.py → utils/__init__.py} +2163 -2772
- swift/common/utils/base.py +131 -0
- swift/common/utils/config.py +433 -0
- swift/common/utils/ipaddrs.py +256 -0
- swift/common/utils/libc.py +345 -0
- swift/common/utils/logs.py +859 -0
- swift/common/utils/timestamp.py +412 -0
- swift/common/wsgi.py +553 -535
- swift/container/auditor.py +14 -100
- swift/container/backend.py +490 -231
- swift/container/reconciler.py +126 -37
- swift/container/replicator.py +96 -22
- swift/container/server.py +358 -165
- swift/container/sharder.py +1540 -684
- swift/container/sync.py +94 -88
- swift/container/updater.py +53 -32
- swift/obj/auditor.py +153 -35
- swift/obj/diskfile.py +466 -217
- swift/obj/expirer.py +406 -124
- swift/obj/mem_diskfile.py +7 -4
- swift/obj/mem_server.py +1 -0
- swift/obj/reconstructor.py +523 -262
- swift/obj/replicator.py +249 -188
- swift/obj/server.py +207 -122
- swift/obj/ssync_receiver.py +145 -85
- swift/obj/ssync_sender.py +113 -54
- swift/obj/updater.py +652 -139
- swift/obj/watchers/__init__.py +0 -0
- swift/obj/watchers/dark_data.py +213 -0
- swift/proxy/controllers/account.py +11 -11
- swift/proxy/controllers/base.py +848 -604
- swift/proxy/controllers/container.py +433 -92
- swift/proxy/controllers/info.py +3 -2
- swift/proxy/controllers/obj.py +1000 -489
- swift/proxy/server.py +185 -112
- {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/AUTHORS +58 -11
- {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/METADATA +51 -56
- swift-2.35.0.dist-info/RECORD +201 -0
- {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/WHEEL +1 -1
- {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/entry_points.txt +43 -0
- swift-2.35.0.dist-info/pbr.json +1 -0
- swift/locale/de/LC_MESSAGES/swift.po +0 -1216
- swift/locale/en_GB/LC_MESSAGES/swift.po +0 -1207
- swift/locale/es/LC_MESSAGES/swift.po +0 -1085
- swift/locale/fr/LC_MESSAGES/swift.po +0 -909
- swift/locale/it/LC_MESSAGES/swift.po +0 -894
- swift/locale/ja/LC_MESSAGES/swift.po +0 -965
- swift/locale/ko_KR/LC_MESSAGES/swift.po +0 -964
- swift/locale/pt_BR/LC_MESSAGES/swift.po +0 -881
- swift/locale/ru/LC_MESSAGES/swift.po +0 -891
- swift/locale/tr_TR/LC_MESSAGES/swift.po +0 -832
- swift/locale/zh_CN/LC_MESSAGES/swift.po +0 -833
- swift/locale/zh_TW/LC_MESSAGES/swift.po +0 -838
- swift-2.23.3.data/scripts/swift-account-auditor +0 -23
- swift-2.23.3.data/scripts/swift-account-info +0 -51
- swift-2.23.3.data/scripts/swift-account-reaper +0 -23
- swift-2.23.3.data/scripts/swift-account-replicator +0 -34
- swift-2.23.3.data/scripts/swift-account-server +0 -23
- swift-2.23.3.data/scripts/swift-container-auditor +0 -23
- swift-2.23.3.data/scripts/swift-container-info +0 -55
- swift-2.23.3.data/scripts/swift-container-reconciler +0 -21
- swift-2.23.3.data/scripts/swift-container-replicator +0 -34
- swift-2.23.3.data/scripts/swift-container-sharder +0 -37
- swift-2.23.3.data/scripts/swift-container-sync +0 -23
- swift-2.23.3.data/scripts/swift-container-updater +0 -23
- swift-2.23.3.data/scripts/swift-dispersion-report +0 -24
- swift-2.23.3.data/scripts/swift-form-signature +0 -20
- swift-2.23.3.data/scripts/swift-init +0 -119
- swift-2.23.3.data/scripts/swift-object-auditor +0 -29
- swift-2.23.3.data/scripts/swift-object-expirer +0 -33
- swift-2.23.3.data/scripts/swift-object-info +0 -60
- swift-2.23.3.data/scripts/swift-object-reconstructor +0 -33
- swift-2.23.3.data/scripts/swift-object-relinker +0 -41
- swift-2.23.3.data/scripts/swift-object-replicator +0 -37
- swift-2.23.3.data/scripts/swift-object-server +0 -27
- swift-2.23.3.data/scripts/swift-object-updater +0 -23
- swift-2.23.3.data/scripts/swift-proxy-server +0 -23
- swift-2.23.3.data/scripts/swift-recon +0 -24
- swift-2.23.3.data/scripts/swift-ring-builder +0 -24
- swift-2.23.3.data/scripts/swift-ring-builder-analyzer +0 -22
- swift-2.23.3.data/scripts/swift-ring-composer +0 -22
- swift-2.23.3.dist-info/RECORD +0 -220
- swift-2.23.3.dist-info/pbr.json +0 -1
- {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/LICENSE +0 -0
- {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/top_level.txt +0 -0
swift/common/memcached.py
CHANGED
@@ -44,19 +44,23 @@ version is at:
|
|
44
44
|
http://github.com/memcached/memcached/blob/1.4.2/doc/protocol.txt
|
45
45
|
"""
|
46
46
|
|
47
|
-
import
|
48
|
-
import six.moves.cPickle as pickle
|
47
|
+
import os
|
49
48
|
import json
|
50
49
|
import logging
|
51
|
-
|
50
|
+
# the name of 'time' module is changed to 'tm', to avoid changing the
|
51
|
+
# signatures of member functions in this file.
|
52
|
+
import time as tm
|
52
53
|
from bisect import bisect
|
53
|
-
from hashlib import md5
|
54
54
|
|
55
|
-
from eventlet.green import socket
|
55
|
+
from eventlet.green import socket, ssl
|
56
56
|
from eventlet.pools import Pool
|
57
57
|
from eventlet import Timeout
|
58
|
-
from
|
58
|
+
from configparser import ConfigParser, NoSectionError, NoOptionError
|
59
59
|
from swift.common import utils
|
60
|
+
from swift.common.exceptions import MemcacheConnectionError, \
|
61
|
+
MemcacheIncrNotFoundError, MemcachePoolTimeout
|
62
|
+
from swift.common.utils import md5, human_readable, config_true_value, \
|
63
|
+
memcached_timing_stats
|
60
64
|
|
61
65
|
DEFAULT_MEMCACHED_PORT = 11211
|
62
66
|
|
@@ -66,23 +70,27 @@ IO_TIMEOUT = 2.0
|
|
66
70
|
PICKLE_FLAG = 1
|
67
71
|
JSON_FLAG = 2
|
68
72
|
NODE_WEIGHT = 50
|
69
|
-
PICKLE_PROTOCOL = 2
|
70
73
|
TRY_COUNT = 3
|
71
74
|
|
72
75
|
# if ERROR_LIMIT_COUNT errors occur in ERROR_LIMIT_TIME seconds, the server
|
73
76
|
# will be considered failed for ERROR_LIMIT_DURATION seconds.
|
74
77
|
ERROR_LIMIT_COUNT = 10
|
75
|
-
ERROR_LIMIT_TIME = 60
|
76
|
-
|
78
|
+
ERROR_LIMIT_TIME = ERROR_LIMIT_DURATION = 60
|
79
|
+
DEFAULT_ITEM_SIZE_WARNING_THRESHOLD = -1
|
80
|
+
|
81
|
+
# Different sample rates for emitting Memcached timing stats.
|
82
|
+
TIMING_SAMPLE_RATE_HIGH = 0.1
|
83
|
+
TIMING_SAMPLE_RATE_MEDIUM = 0.01
|
84
|
+
TIMING_SAMPLE_RATE_LOW = 0.001
|
85
|
+
|
86
|
+
# The max value of a delta expiration time.
|
87
|
+
EXPTIME_MAXDELTA = 30 * 24 * 60 * 60
|
77
88
|
|
78
89
|
|
79
90
|
def md5hash(key):
|
80
91
|
if not isinstance(key, bytes):
|
81
|
-
|
82
|
-
|
83
|
-
else:
|
84
|
-
key = key.encode('utf-8', errors='surrogateescape')
|
85
|
-
return md5(key).hexdigest().encode('ascii')
|
92
|
+
key = key.encode('utf-8', errors='surrogateescape')
|
93
|
+
return md5(key, usedforsecurity=False).hexdigest().encode('ascii')
|
86
94
|
|
87
95
|
|
88
96
|
def sanitize_timeout(timeout):
|
@@ -92,8 +100,8 @@ def sanitize_timeout(timeout):
|
|
92
100
|
translates negative values to mean a delta of 30 days in seconds (and 1
|
93
101
|
additional second), client beware.
|
94
102
|
"""
|
95
|
-
if timeout >
|
96
|
-
timeout +=
|
103
|
+
if timeout > EXPTIME_MAXDELTA:
|
104
|
+
timeout += tm.time()
|
97
105
|
return int(timeout)
|
98
106
|
|
99
107
|
|
@@ -111,14 +119,6 @@ def set_msg(key, flags, timeout, value):
|
|
111
119
|
]) + (b'\r\n' + value + b'\r\n')
|
112
120
|
|
113
121
|
|
114
|
-
class MemcacheConnectionError(Exception):
|
115
|
-
pass
|
116
|
-
|
117
|
-
|
118
|
-
class MemcachePoolTimeout(Timeout):
|
119
|
-
pass
|
120
|
-
|
121
|
-
|
122
122
|
class MemcacheConnPool(Pool):
|
123
123
|
"""
|
124
124
|
Connection pool for Memcache Connections
|
@@ -141,19 +141,54 @@ class MemcacheConnPool(Pool):
|
|
141
141
|
family, socktype, proto, canonname, sockaddr = addrs[0]
|
142
142
|
sock = socket.socket(family, socket.SOCK_STREAM)
|
143
143
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
144
|
+
try:
|
145
|
+
with Timeout(self._connect_timeout):
|
146
|
+
sock.connect(sockaddr)
|
147
|
+
if self._tls_context:
|
148
|
+
sock = self._tls_context.wrap_socket(sock,
|
149
|
+
server_hostname=self.host)
|
150
|
+
except (Exception, Timeout):
|
151
|
+
sock.close()
|
152
|
+
raise
|
149
153
|
return (sock.makefile('rwb'), sock)
|
150
154
|
|
151
155
|
def get(self):
|
152
156
|
fp, sock = super(MemcacheConnPool, self).get()
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
+
try:
|
158
|
+
if fp is None:
|
159
|
+
# An error happened previously, so we need a new connection
|
160
|
+
fp, sock = self.create()
|
161
|
+
return fp, sock
|
162
|
+
except MemcachePoolTimeout:
|
163
|
+
# This is the only place that knows an item was successfully taken
|
164
|
+
# from the pool, so it has to be responsible for repopulating it.
|
165
|
+
# Any other errors should get handled in _get_conns(); see the
|
166
|
+
# comment about timeouts during create() there.
|
167
|
+
self.put((None, None))
|
168
|
+
raise
|
169
|
+
|
170
|
+
|
171
|
+
class MemcacheCommand(object):
|
172
|
+
"""
|
173
|
+
Helper class that encapsulates common parameters of a command.
|
174
|
+
|
175
|
+
:param method: the name of the MemcacheRing method that was called.
|
176
|
+
:param key: the memcached key.
|
177
|
+
"""
|
178
|
+
__slots__ = ('method', 'key', 'command', 'hash_key')
|
179
|
+
|
180
|
+
def __init__(self, method, key):
|
181
|
+
self.method = method
|
182
|
+
self.key = key
|
183
|
+
self.command = method.encode()
|
184
|
+
self.hash_key = md5hash(key)
|
185
|
+
|
186
|
+
@property
|
187
|
+
def key_prefix(self):
|
188
|
+
# get the prefix of a user provided memcache key by removing the
|
189
|
+
# content after the last '/', all current usages within swift are using
|
190
|
+
# prefix, such as "shard-updating-v2", "nvratelimit" and etc.
|
191
|
+
return self.key.rsplit('/', 1)[0]
|
157
192
|
|
158
193
|
|
159
194
|
class MemcacheRing(object):
|
@@ -161,13 +196,21 @@ class MemcacheRing(object):
|
|
161
196
|
Simple, consistent-hashed memcache client.
|
162
197
|
"""
|
163
198
|
|
164
|
-
def __init__(
|
165
|
-
|
166
|
-
|
167
|
-
|
199
|
+
def __init__(
|
200
|
+
self, servers, connect_timeout=CONN_TIMEOUT,
|
201
|
+
io_timeout=IO_TIMEOUT, pool_timeout=POOL_TIMEOUT,
|
202
|
+
tries=TRY_COUNT,
|
203
|
+
max_conns=2, tls_context=None, logger=None,
|
204
|
+
error_limit_count=ERROR_LIMIT_COUNT,
|
205
|
+
error_limit_time=ERROR_LIMIT_TIME,
|
206
|
+
error_limit_duration=ERROR_LIMIT_DURATION,
|
207
|
+
item_size_warning_threshold=DEFAULT_ITEM_SIZE_WARNING_THRESHOLD):
|
168
208
|
self._ring = {}
|
169
209
|
self._errors = dict(((serv, []) for serv in servers))
|
170
210
|
self._error_limited = dict(((serv, 0) for serv in servers))
|
211
|
+
self._error_limit_count = error_limit_count
|
212
|
+
self._error_limit_time = error_limit_time
|
213
|
+
self._error_limit_duration = error_limit_duration
|
171
214
|
for server in sorted(servers):
|
172
215
|
for i in range(NODE_WEIGHT):
|
173
216
|
self._ring[md5hash('%s-%s' % (server, i))] = server
|
@@ -180,20 +223,73 @@ class MemcacheRing(object):
|
|
180
223
|
self._connect_timeout = connect_timeout
|
181
224
|
self._io_timeout = io_timeout
|
182
225
|
self._pool_timeout = pool_timeout
|
183
|
-
|
184
|
-
|
226
|
+
if logger is None:
|
227
|
+
self.logger = logging.getLogger()
|
228
|
+
else:
|
229
|
+
self.logger = logger
|
230
|
+
self.item_size_warning_threshold = item_size_warning_threshold
|
185
231
|
|
186
|
-
|
187
|
-
|
232
|
+
@property
|
233
|
+
def memcache_servers(self):
|
234
|
+
return list(self._client_cache.keys())
|
235
|
+
|
236
|
+
def _log_error(self, server, cmd, action, msg):
|
237
|
+
self.logger.error(
|
238
|
+
"Error %(action)s to memcached: %(server)s"
|
239
|
+
": with key_prefix %(key_prefix)s, method %(method)s: %(msg)s",
|
240
|
+
{'action': action, 'server': server, 'key_prefix': cmd.key_prefix,
|
241
|
+
'method': cmd.method, 'msg': msg})
|
242
|
+
|
243
|
+
"""
|
244
|
+
Handles exceptions.
|
245
|
+
|
246
|
+
:param server: a server.
|
247
|
+
:param e: an exception.
|
248
|
+
:param cmd: an instance of MemcacheCommand.
|
249
|
+
:param conn_start_time: the time at which the failed operation started.
|
250
|
+
:param action: a verb describing the operation.
|
251
|
+
:param sock: an optional socket that needs to be closed by this method.
|
252
|
+
:param fp: an optional file pointer that needs to be closed by this method.
|
253
|
+
:param got_connection: if ``True``, the server's connection will be reset
|
254
|
+
in the cached connection pool.
|
255
|
+
"""
|
256
|
+
def _exception_occurred(self, server, e, cmd, conn_start_time,
|
257
|
+
action='talking', sock=None,
|
258
|
+
fp=None, got_connection=True):
|
188
259
|
if isinstance(e, Timeout):
|
189
|
-
|
190
|
-
|
260
|
+
self.logger.error(
|
261
|
+
"Timeout %(action)s to memcached: %(server)s"
|
262
|
+
": with key_prefix %(key_prefix)s, method %(method)s, "
|
263
|
+
"config_timeout %(config_timeout)s, time_spent %(time_spent)s",
|
264
|
+
{'action': action, 'server': server,
|
265
|
+
'key_prefix': cmd.key_prefix, 'method': cmd.method,
|
266
|
+
'config_timeout': e.seconds,
|
267
|
+
'time_spent': tm.time() - conn_start_time})
|
268
|
+
self.logger.timing_since(
|
269
|
+
'memcached.' + cmd.method + '.timeout.timing',
|
270
|
+
conn_start_time)
|
191
271
|
elif isinstance(e, (socket.error, MemcacheConnectionError)):
|
192
|
-
|
193
|
-
|
272
|
+
self.logger.error(
|
273
|
+
"Error %(action)s to memcached: %(server)s: "
|
274
|
+
"with key_prefix %(key_prefix)s, method %(method)s, "
|
275
|
+
"time_spent %(time_spent)s, %(err)s",
|
276
|
+
{'action': action, 'server': server,
|
277
|
+
'key_prefix': cmd.key_prefix, 'method': cmd.method,
|
278
|
+
'time_spent': tm.time() - conn_start_time, 'err': e})
|
279
|
+
self.logger.timing_since(
|
280
|
+
'memcached.' + cmd.method + '.conn_err.timing',
|
281
|
+
conn_start_time)
|
194
282
|
else:
|
195
|
-
|
196
|
-
|
283
|
+
self.logger.exception(
|
284
|
+
"Error %(action)s to memcached: %(server)s"
|
285
|
+
": with key_prefix %(key_prefix)s, method %(method)s, "
|
286
|
+
"time_spent %(time_spent)s",
|
287
|
+
{'action': action, 'server': server,
|
288
|
+
'key_prefix': cmd.key_prefix, 'method': cmd.method,
|
289
|
+
'time_spent': tm.time() - conn_start_time})
|
290
|
+
self.logger.timing_since(
|
291
|
+
'memcached.' + cmd.method + '.errors.timing', conn_start_time)
|
292
|
+
|
197
293
|
try:
|
198
294
|
if fp:
|
199
295
|
fp.close()
|
@@ -210,73 +306,93 @@ class MemcacheRing(object):
|
|
210
306
|
# We need to return something to the pool
|
211
307
|
# A new connection will be created the next time it is retrieved
|
212
308
|
self._return_conn(server, None, None)
|
213
|
-
|
214
|
-
|
215
|
-
|
309
|
+
|
310
|
+
if isinstance(e, MemcacheIncrNotFoundError):
|
311
|
+
# these errors can be caused by other greenthreads not yielding to
|
312
|
+
# the incr greenthread often enough, rather than a server problem,
|
313
|
+
# so don't error limit the server
|
314
|
+
return
|
315
|
+
|
316
|
+
if self._error_limit_time <= 0 or self._error_limit_duration <= 0:
|
317
|
+
return
|
318
|
+
|
319
|
+
now = tm.time()
|
320
|
+
self._errors[server].append(now)
|
321
|
+
if len(self._errors[server]) > self._error_limit_count:
|
216
322
|
self._errors[server] = [err for err in self._errors[server]
|
217
|
-
if err > now -
|
218
|
-
if len(self._errors[server]) >
|
219
|
-
self._error_limited[server] = now +
|
220
|
-
|
323
|
+
if err > now - self._error_limit_time]
|
324
|
+
if len(self._errors[server]) > self._error_limit_count:
|
325
|
+
self._error_limited[server] = now + self._error_limit_duration
|
326
|
+
self.logger.error('Error limiting server %s', server)
|
221
327
|
|
222
|
-
def _get_conns(self,
|
328
|
+
def _get_conns(self, cmd):
|
223
329
|
"""
|
224
330
|
Retrieves a server conn from the pool, or connects a new one.
|
225
331
|
Chooses the server based on a consistent hash of "key".
|
332
|
+
|
333
|
+
:param cmd: an instance of MemcacheCommand.
|
334
|
+
:return: generator to serve memcached connection
|
226
335
|
"""
|
227
|
-
pos = bisect(self._sorted,
|
336
|
+
pos = bisect(self._sorted, cmd.hash_key)
|
228
337
|
served = []
|
338
|
+
any_yielded = False
|
229
339
|
while len(served) < self._tries:
|
230
340
|
pos = (pos + 1) % len(self._sorted)
|
231
341
|
server = self._ring[self._sorted[pos]]
|
232
342
|
if server in served:
|
233
343
|
continue
|
234
344
|
served.append(server)
|
235
|
-
|
345
|
+
pool_start_time = tm.time()
|
346
|
+
if self._error_limited[server] > pool_start_time:
|
236
347
|
continue
|
237
348
|
sock = None
|
238
349
|
try:
|
239
350
|
with MemcachePoolTimeout(self._pool_timeout):
|
240
351
|
fp, sock = self._client_cache[server].get()
|
352
|
+
any_yielded = True
|
241
353
|
yield server, fp, sock
|
242
354
|
except MemcachePoolTimeout as e:
|
243
|
-
self._exception_occurred(
|
244
|
-
|
245
|
-
|
355
|
+
self._exception_occurred(server, e, cmd, pool_start_time,
|
356
|
+
action='getting a connection',
|
357
|
+
got_connection=False)
|
246
358
|
except (Exception, Timeout) as e:
|
247
359
|
# Typically a Timeout exception caught here is the one raised
|
248
360
|
# by the create() method of this server's MemcacheConnPool
|
249
361
|
# object.
|
250
|
-
self._exception_occurred(
|
251
|
-
|
362
|
+
self._exception_occurred(server, e, cmd, pool_start_time,
|
363
|
+
action='connecting', sock=sock)
|
364
|
+
if not any_yielded:
|
365
|
+
self._log_error('ALL', cmd, 'connecting',
|
366
|
+
'No more memcached servers to try')
|
252
367
|
|
253
368
|
def _return_conn(self, server, fp, sock):
|
254
369
|
"""Returns a server connection to the pool."""
|
255
370
|
self._client_cache[server].put((fp, sock))
|
256
371
|
|
372
|
+
# Sample rates of different memcached operations are based on generic
|
373
|
+
# swift usage patterns.
|
374
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_HIGH)
|
257
375
|
def set(self, key, value, serialize=True, time=0,
|
258
|
-
min_compress_len=0):
|
376
|
+
min_compress_len=0, raise_on_error=False):
|
259
377
|
"""
|
260
378
|
Set a key/value pair in memcache
|
261
379
|
|
262
380
|
:param key: key
|
263
381
|
:param value: value
|
264
382
|
:param serialize: if True, value is serialized with JSON before sending
|
265
|
-
to memcache
|
266
|
-
pickle instead of JSON (to avoid cache poisoning)
|
383
|
+
to memcache
|
267
384
|
:param time: the time to live
|
268
385
|
:param min_compress_len: minimum compress length, this parameter was
|
269
386
|
added to keep the signature compatible with
|
270
387
|
python-memcached interface. This
|
271
388
|
implementation ignores it.
|
389
|
+
:param raise_on_error: if True, propagate Timeouts and other errors.
|
390
|
+
By default, errors are ignored.
|
272
391
|
"""
|
273
|
-
|
392
|
+
cmd = MemcacheCommand('set', key)
|
274
393
|
timeout = sanitize_timeout(time)
|
275
394
|
flags = 0
|
276
|
-
if serialize
|
277
|
-
value = pickle.dumps(value, PICKLE_PROTOCOL)
|
278
|
-
flags |= PICKLE_FLAG
|
279
|
-
elif serialize:
|
395
|
+
if serialize:
|
280
396
|
if isinstance(value, bytes):
|
281
397
|
value = value.decode('utf8')
|
282
398
|
value = json.dumps(value).encode('ascii')
|
@@ -284,55 +400,94 @@ class MemcacheRing(object):
|
|
284
400
|
elif not isinstance(value, bytes):
|
285
401
|
value = str(value).encode('utf-8')
|
286
402
|
|
287
|
-
|
403
|
+
if 0 <= self.item_size_warning_threshold <= len(value):
|
404
|
+
self.logger.warning(
|
405
|
+
"Item size larger than warning threshold: "
|
406
|
+
"%d (%s) >= %d (%s)", len(value),
|
407
|
+
human_readable(len(value)),
|
408
|
+
self.item_size_warning_threshold,
|
409
|
+
human_readable(self.item_size_warning_threshold))
|
410
|
+
|
411
|
+
for (server, fp, sock) in self._get_conns(cmd):
|
412
|
+
conn_start_time = tm.time()
|
288
413
|
try:
|
289
414
|
with Timeout(self._io_timeout):
|
290
|
-
sock.sendall(set_msg(
|
415
|
+
sock.sendall(set_msg(cmd.hash_key, flags, timeout, value))
|
291
416
|
# Wait for the set to complete
|
292
|
-
fp.readline()
|
417
|
+
msg = fp.readline().strip()
|
418
|
+
if msg != b'STORED':
|
419
|
+
msg = msg.decode('ascii')
|
420
|
+
raise MemcacheConnectionError('failed set: %s' % msg)
|
293
421
|
self._return_conn(server, fp, sock)
|
294
422
|
return
|
295
423
|
except (Exception, Timeout) as e:
|
296
|
-
self._exception_occurred(server, e,
|
297
|
-
|
298
|
-
|
424
|
+
self._exception_occurred(server, e, cmd, conn_start_time,
|
425
|
+
sock=sock, fp=fp)
|
426
|
+
if raise_on_error:
|
427
|
+
raise MemcacheConnectionError(
|
428
|
+
"No memcached connections succeeded.")
|
429
|
+
|
430
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_MEDIUM)
|
431
|
+
def get(self, key, raise_on_error=False):
|
299
432
|
"""
|
300
433
|
Gets the object specified by key. It will also unserialize the object
|
301
|
-
before returning if it is serialized in memcache with JSON
|
302
|
-
is pickled and unpickling is allowed.
|
434
|
+
before returning if it is serialized in memcache with JSON.
|
303
435
|
|
304
436
|
:param key: key
|
437
|
+
:param raise_on_error: if True, propagate Timeouts and other errors.
|
438
|
+
By default, errors are treated as cache misses.
|
305
439
|
:returns: value of the key in memcache
|
306
440
|
"""
|
307
|
-
|
441
|
+
cmd = MemcacheCommand('get', key)
|
308
442
|
value = None
|
309
|
-
for (server, fp, sock) in self._get_conns(
|
443
|
+
for (server, fp, sock) in self._get_conns(cmd):
|
444
|
+
conn_start_time = tm.time()
|
310
445
|
try:
|
311
446
|
with Timeout(self._io_timeout):
|
312
|
-
sock.sendall(b'get ' +
|
447
|
+
sock.sendall(b'get ' + cmd.hash_key + b'\r\n')
|
313
448
|
line = fp.readline().strip().split()
|
314
449
|
while True:
|
315
450
|
if not line:
|
316
451
|
raise MemcacheConnectionError('incomplete read')
|
317
452
|
if line[0].upper() == b'END':
|
318
453
|
break
|
319
|
-
if line[0].upper() == b'VALUE' and
|
454
|
+
if (line[0].upper() == b'VALUE' and
|
455
|
+
line[1] == cmd.hash_key):
|
320
456
|
size = int(line[3])
|
321
457
|
value = fp.read(size)
|
322
458
|
if int(line[2]) & PICKLE_FLAG:
|
323
|
-
|
324
|
-
|
325
|
-
else:
|
326
|
-
value = None
|
327
|
-
elif int(line[2]) & JSON_FLAG:
|
459
|
+
value = None
|
460
|
+
if int(line[2]) & JSON_FLAG:
|
328
461
|
value = json.loads(value)
|
329
462
|
fp.readline()
|
330
463
|
line = fp.readline().strip().split()
|
331
464
|
self._return_conn(server, fp, sock)
|
332
465
|
return value
|
333
466
|
except (Exception, Timeout) as e:
|
334
|
-
self._exception_occurred(server, e,
|
335
|
-
|
467
|
+
self._exception_occurred(server, e, cmd, conn_start_time,
|
468
|
+
sock=sock, fp=fp)
|
469
|
+
if raise_on_error:
|
470
|
+
raise MemcacheConnectionError(
|
471
|
+
"No memcached connections succeeded.")
|
472
|
+
|
473
|
+
def _incr_or_decr(self, fp, sock, cmd, delta):
|
474
|
+
sock.sendall(b' '.join([cmd.command, cmd.hash_key, delta]) + b'\r\n')
|
475
|
+
line = fp.readline().strip().split()
|
476
|
+
if not line:
|
477
|
+
raise MemcacheConnectionError('incomplete read')
|
478
|
+
if line[0].upper() == b'NOT_FOUND':
|
479
|
+
return None
|
480
|
+
return int(line[0].strip())
|
481
|
+
|
482
|
+
def _add(self, fp, sock, cmd, add_val, timeout):
|
483
|
+
sock.sendall(b' '.join([
|
484
|
+
b'add', cmd.hash_key, b'0', str(timeout).encode('ascii'),
|
485
|
+
str(len(add_val)).encode('ascii')
|
486
|
+
]) + b'\r\n' + add_val + b'\r\n')
|
487
|
+
line = fp.readline().strip().split()
|
488
|
+
return None if line[0].upper() == b'NOT_STORED' else int(add_val)
|
489
|
+
|
490
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_LOW)
|
336
491
|
def incr(self, key, delta=1, time=0):
|
337
492
|
"""
|
338
493
|
Increments a key which has a numeric value by delta.
|
@@ -350,44 +505,35 @@ class MemcacheRing(object):
|
|
350
505
|
:returns: result of incrementing
|
351
506
|
:raises MemcacheConnectionError:
|
352
507
|
"""
|
353
|
-
|
354
|
-
|
355
|
-
if delta < 0:
|
356
|
-
command = b'decr'
|
357
|
-
delta = str(abs(int(delta))).encode('ascii')
|
508
|
+
cmd = MemcacheCommand('incr' if delta >= 0 else 'decr', key)
|
509
|
+
delta_val = str(abs(int(delta))).encode('ascii')
|
358
510
|
timeout = sanitize_timeout(time)
|
359
|
-
for (server, fp, sock) in self._get_conns(
|
511
|
+
for (server, fp, sock) in self._get_conns(cmd):
|
512
|
+
conn_start_time = tm.time()
|
360
513
|
try:
|
361
514
|
with Timeout(self._io_timeout):
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
if line[0].upper() == b'NOT_STORED':
|
377
|
-
sock.sendall(b' '.join([
|
378
|
-
command, key, delta]) + b'\r\n')
|
379
|
-
line = fp.readline().strip().split()
|
380
|
-
ret = int(line[0].strip())
|
381
|
-
else:
|
382
|
-
ret = int(add_val)
|
383
|
-
else:
|
384
|
-
ret = int(line[0].strip())
|
515
|
+
new_val = self._incr_or_decr(fp, sock, cmd, delta_val)
|
516
|
+
if new_val is None:
|
517
|
+
add_val = b'0' if cmd.method == 'decr' else delta_val
|
518
|
+
new_val = self._add(fp, sock, cmd, add_val, timeout)
|
519
|
+
if new_val is None:
|
520
|
+
new_val = self._incr_or_decr(
|
521
|
+
fp, sock, cmd, delta_val)
|
522
|
+
if new_val is None:
|
523
|
+
# This can happen if this thread takes more
|
524
|
+
# than the TTL to get from the first failed
|
525
|
+
# incr to the second incr, during which time
|
526
|
+
# the key was concurrently added and expired.
|
527
|
+
raise MemcacheIncrNotFoundError(
|
528
|
+
'expired ttl=%s' % time)
|
385
529
|
self._return_conn(server, fp, sock)
|
386
|
-
return
|
530
|
+
return new_val
|
387
531
|
except (Exception, Timeout) as e:
|
388
|
-
self._exception_occurred(server, e,
|
389
|
-
|
532
|
+
self._exception_occurred(server, e, cmd, conn_start_time,
|
533
|
+
sock=sock, fp=fp)
|
534
|
+
raise MemcacheConnectionError("No memcached connections succeeded.")
|
390
535
|
|
536
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_LOW)
|
391
537
|
def decr(self, key, delta=1, time=0):
|
392
538
|
"""
|
393
539
|
Decrements a key which has a numeric value by delta. Calls incr with
|
@@ -403,24 +549,32 @@ class MemcacheRing(object):
|
|
403
549
|
"""
|
404
550
|
return self.incr(key, delta=-delta, time=time)
|
405
551
|
|
406
|
-
|
552
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_HIGH)
|
553
|
+
def delete(self, key, server_key=None):
|
407
554
|
"""
|
408
555
|
Deletes a key/value pair from memcache.
|
409
556
|
|
410
557
|
:param key: key to be deleted
|
558
|
+
:param server_key: key to use in determining which server in the ring
|
559
|
+
is used
|
411
560
|
"""
|
412
|
-
|
413
|
-
|
561
|
+
cmd = server_cmd = MemcacheCommand('delete', key)
|
562
|
+
if server_key:
|
563
|
+
server_cmd = MemcacheCommand('delete', server_key)
|
564
|
+
for (server, fp, sock) in self._get_conns(server_cmd):
|
565
|
+
conn_start_time = tm.time()
|
414
566
|
try:
|
415
567
|
with Timeout(self._io_timeout):
|
416
|
-
sock.sendall(b'delete ' +
|
568
|
+
sock.sendall(b'delete ' + cmd.hash_key + b'\r\n')
|
417
569
|
# Wait for the delete to complete
|
418
570
|
fp.readline()
|
419
571
|
self._return_conn(server, fp, sock)
|
420
572
|
return
|
421
573
|
except (Exception, Timeout) as e:
|
422
|
-
self._exception_occurred(server, e,
|
574
|
+
self._exception_occurred(server, e, cmd, conn_start_time,
|
575
|
+
sock=sock, fp=fp)
|
423
576
|
|
577
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_HIGH)
|
424
578
|
def set_multi(self, mapping, server_key, serialize=True, time=0,
|
425
579
|
min_compress_len=0):
|
426
580
|
"""
|
@@ -430,30 +584,27 @@ class MemcacheRing(object):
|
|
430
584
|
:param server_key: key to use in determining which server in the ring
|
431
585
|
is used
|
432
586
|
:param serialize: if True, value is serialized with JSON before sending
|
433
|
-
to memcache
|
434
|
-
pickle instead of JSON (to avoid cache poisoning)
|
587
|
+
to memcache.
|
435
588
|
:param time: the time to live
|
436
589
|
:min_compress_len: minimum compress length, this parameter was added
|
437
590
|
to keep the signature compatible with
|
438
591
|
python-memcached interface. This implementation
|
439
592
|
ignores it
|
440
593
|
"""
|
441
|
-
|
594
|
+
cmd = MemcacheCommand('set_multi', server_key)
|
442
595
|
timeout = sanitize_timeout(time)
|
443
596
|
msg = []
|
444
597
|
for key, value in mapping.items():
|
445
598
|
key = md5hash(key)
|
446
599
|
flags = 0
|
447
|
-
if serialize
|
448
|
-
value = pickle.dumps(value, PICKLE_PROTOCOL)
|
449
|
-
flags |= PICKLE_FLAG
|
450
|
-
elif serialize:
|
600
|
+
if serialize:
|
451
601
|
if isinstance(value, bytes):
|
452
602
|
value = value.decode('utf8')
|
453
603
|
value = json.dumps(value).encode('ascii')
|
454
604
|
flags |= JSON_FLAG
|
455
605
|
msg.append(set_msg(key, flags, timeout, value))
|
456
|
-
for (server, fp, sock) in self._get_conns(
|
606
|
+
for (server, fp, sock) in self._get_conns(cmd):
|
607
|
+
conn_start_time = tm.time()
|
457
608
|
try:
|
458
609
|
with Timeout(self._io_timeout):
|
459
610
|
sock.sendall(b''.join(msg))
|
@@ -463,8 +614,10 @@ class MemcacheRing(object):
|
|
463
614
|
self._return_conn(server, fp, sock)
|
464
615
|
return
|
465
616
|
except (Exception, Timeout) as e:
|
466
|
-
self._exception_occurred(server, e,
|
617
|
+
self._exception_occurred(server, e, cmd, conn_start_time,
|
618
|
+
sock=sock, fp=fp)
|
467
619
|
|
620
|
+
@memcached_timing_stats(sample_rate=TIMING_SAMPLE_RATE_HIGH)
|
468
621
|
def get_multi(self, keys, server_key):
|
469
622
|
"""
|
470
623
|
Gets multiple values from memcache for the given keys.
|
@@ -474,12 +627,13 @@ class MemcacheRing(object):
|
|
474
627
|
is used
|
475
628
|
:returns: list of values
|
476
629
|
"""
|
477
|
-
|
478
|
-
|
479
|
-
for (server, fp, sock) in self._get_conns(
|
630
|
+
cmd = MemcacheCommand('get_multi', server_key)
|
631
|
+
hash_keys = [md5hash(key) for key in keys]
|
632
|
+
for (server, fp, sock) in self._get_conns(cmd):
|
633
|
+
conn_start_time = tm.time()
|
480
634
|
try:
|
481
635
|
with Timeout(self._io_timeout):
|
482
|
-
sock.sendall(b'get ' + b' '.join(
|
636
|
+
sock.sendall(b'get ' + b' '.join(hash_keys) + b'\r\n')
|
483
637
|
line = fp.readline().strip().split()
|
484
638
|
responses = {}
|
485
639
|
while True:
|
@@ -491,17 +645,14 @@ class MemcacheRing(object):
|
|
491
645
|
size = int(line[3])
|
492
646
|
value = fp.read(size)
|
493
647
|
if int(line[2]) & PICKLE_FLAG:
|
494
|
-
|
495
|
-
value = pickle.loads(value)
|
496
|
-
else:
|
497
|
-
value = None
|
648
|
+
value = None
|
498
649
|
elif int(line[2]) & JSON_FLAG:
|
499
650
|
value = json.loads(value)
|
500
651
|
responses[line[1]] = value
|
501
652
|
fp.readline()
|
502
653
|
line = fp.readline().strip().split()
|
503
654
|
values = []
|
504
|
-
for key in
|
655
|
+
for key in hash_keys:
|
505
656
|
if key in responses:
|
506
657
|
values.append(responses[key])
|
507
658
|
else:
|
@@ -509,4 +660,98 @@ class MemcacheRing(object):
|
|
509
660
|
self._return_conn(server, fp, sock)
|
510
661
|
return values
|
511
662
|
except (Exception, Timeout) as e:
|
512
|
-
self._exception_occurred(server, e,
|
663
|
+
self._exception_occurred(server, e, cmd, conn_start_time,
|
664
|
+
sock=sock, fp=fp)
|
665
|
+
|
666
|
+
|
667
|
+
def load_memcache(conf, logger):
|
668
|
+
"""
|
669
|
+
Build a MemcacheRing object from the given config. It will also use the
|
670
|
+
passed in logger.
|
671
|
+
|
672
|
+
:param conf: a dict, the config options
|
673
|
+
:param logger: a logger
|
674
|
+
"""
|
675
|
+
memcache_servers = conf.get('memcache_servers')
|
676
|
+
try:
|
677
|
+
# Originally, while we documented using memcache_max_connections
|
678
|
+
# we only accepted max_connections
|
679
|
+
max_conns = int(conf.get('memcache_max_connections',
|
680
|
+
conf.get('max_connections', 0)))
|
681
|
+
except ValueError:
|
682
|
+
max_conns = 0
|
683
|
+
|
684
|
+
memcache_options = {}
|
685
|
+
if (not memcache_servers
|
686
|
+
or max_conns <= 0):
|
687
|
+
path = os.path.join(conf.get('swift_dir', '/etc/swift'),
|
688
|
+
'memcache.conf')
|
689
|
+
memcache_conf = ConfigParser()
|
690
|
+
if memcache_conf.read(path):
|
691
|
+
# if memcache.conf exists we'll start with those base options
|
692
|
+
try:
|
693
|
+
memcache_options = dict(memcache_conf.items('memcache'))
|
694
|
+
except NoSectionError:
|
695
|
+
pass
|
696
|
+
|
697
|
+
if not memcache_servers:
|
698
|
+
try:
|
699
|
+
memcache_servers = \
|
700
|
+
memcache_conf.get('memcache', 'memcache_servers')
|
701
|
+
except (NoSectionError, NoOptionError):
|
702
|
+
pass
|
703
|
+
if max_conns <= 0:
|
704
|
+
try:
|
705
|
+
new_max_conns = \
|
706
|
+
memcache_conf.get('memcache',
|
707
|
+
'memcache_max_connections')
|
708
|
+
max_conns = int(new_max_conns)
|
709
|
+
except (NoSectionError, NoOptionError, ValueError):
|
710
|
+
pass
|
711
|
+
|
712
|
+
# while memcache.conf options are the base for the memcache
|
713
|
+
# middleware, if you set the same option also in the filter
|
714
|
+
# section of the proxy config it is more specific.
|
715
|
+
memcache_options.update(conf)
|
716
|
+
connect_timeout = float(memcache_options.get(
|
717
|
+
'connect_timeout', CONN_TIMEOUT))
|
718
|
+
pool_timeout = float(memcache_options.get(
|
719
|
+
'pool_timeout', POOL_TIMEOUT))
|
720
|
+
tries = int(memcache_options.get('tries', TRY_COUNT))
|
721
|
+
io_timeout = float(memcache_options.get('io_timeout', IO_TIMEOUT))
|
722
|
+
if config_true_value(memcache_options.get('tls_enabled', 'false')):
|
723
|
+
tls_cafile = memcache_options.get('tls_cafile')
|
724
|
+
tls_certfile = memcache_options.get('tls_certfile')
|
725
|
+
tls_keyfile = memcache_options.get('tls_keyfile')
|
726
|
+
tls_context = ssl.create_default_context(
|
727
|
+
cafile=tls_cafile)
|
728
|
+
if tls_certfile:
|
729
|
+
tls_context.load_cert_chain(tls_certfile, tls_keyfile)
|
730
|
+
else:
|
731
|
+
tls_context = None
|
732
|
+
error_suppression_interval = float(memcache_options.get(
|
733
|
+
'error_suppression_interval', ERROR_LIMIT_TIME))
|
734
|
+
error_suppression_limit = float(memcache_options.get(
|
735
|
+
'error_suppression_limit', ERROR_LIMIT_COUNT))
|
736
|
+
item_size_warning_threshold = int(memcache_options.get(
|
737
|
+
'item_size_warning_threshold', DEFAULT_ITEM_SIZE_WARNING_THRESHOLD))
|
738
|
+
|
739
|
+
if not memcache_servers:
|
740
|
+
memcache_servers = '127.0.0.1:11211'
|
741
|
+
if max_conns <= 0:
|
742
|
+
max_conns = 2
|
743
|
+
|
744
|
+
return MemcacheRing(
|
745
|
+
[s.strip() for s in memcache_servers.split(',')
|
746
|
+
if s.strip()],
|
747
|
+
connect_timeout=connect_timeout,
|
748
|
+
pool_timeout=pool_timeout,
|
749
|
+
tries=tries,
|
750
|
+
io_timeout=io_timeout,
|
751
|
+
max_conns=max_conns,
|
752
|
+
tls_context=tls_context,
|
753
|
+
logger=logger,
|
754
|
+
error_limit_count=error_suppression_limit,
|
755
|
+
error_limit_time=error_suppression_interval,
|
756
|
+
error_limit_duration=error_suppression_interval,
|
757
|
+
item_size_warning_threshold=item_size_warning_threshold)
|