swift 2.31.1__py2.py3-none-any.whl → 2.32.1__py2.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/cli/info.py +9 -2
- swift/cli/ringbuilder.py +5 -1
- swift/common/container_sync_realms.py +6 -7
- swift/common/daemon.py +7 -3
- swift/common/db.py +22 -7
- swift/common/db_replicator.py +19 -20
- swift/common/direct_client.py +63 -14
- swift/common/internal_client.py +24 -3
- swift/common/manager.py +43 -44
- swift/common/memcached.py +168 -74
- swift/common/middleware/__init__.py +4 -0
- swift/common/middleware/account_quotas.py +98 -40
- swift/common/middleware/backend_ratelimit.py +6 -4
- swift/common/middleware/crossdomain.py +21 -8
- swift/common/middleware/listing_formats.py +26 -38
- swift/common/middleware/proxy_logging.py +12 -9
- swift/common/middleware/s3api/controllers/bucket.py +8 -2
- swift/common/middleware/s3api/s3api.py +9 -4
- swift/common/middleware/s3api/s3request.py +32 -24
- swift/common/middleware/s3api/s3response.py +10 -1
- swift/common/middleware/tempauth.py +9 -10
- swift/common/middleware/versioned_writes/__init__.py +0 -3
- swift/common/middleware/versioned_writes/object_versioning.py +22 -5
- swift/common/middleware/x_profile/html_viewer.py +1 -1
- swift/common/middleware/xprofile.py +5 -0
- swift/common/request_helpers.py +1 -2
- swift/common/ring/ring.py +22 -19
- swift/common/swob.py +2 -1
- swift/common/{utils.py → utils/__init__.py} +610 -1146
- swift/common/utils/ipaddrs.py +256 -0
- swift/common/utils/libc.py +345 -0
- swift/common/utils/timestamp.py +399 -0
- swift/common/wsgi.py +70 -39
- swift/container/backend.py +106 -38
- swift/container/server.py +11 -2
- swift/container/sharder.py +34 -15
- swift/locale/de/LC_MESSAGES/swift.po +1 -320
- swift/locale/en_GB/LC_MESSAGES/swift.po +1 -347
- swift/locale/es/LC_MESSAGES/swift.po +1 -279
- swift/locale/fr/LC_MESSAGES/swift.po +1 -209
- swift/locale/it/LC_MESSAGES/swift.po +1 -207
- swift/locale/ja/LC_MESSAGES/swift.po +2 -278
- swift/locale/ko_KR/LC_MESSAGES/swift.po +3 -303
- swift/locale/pt_BR/LC_MESSAGES/swift.po +1 -204
- swift/locale/ru/LC_MESSAGES/swift.po +1 -203
- swift/locale/tr_TR/LC_MESSAGES/swift.po +1 -192
- swift/locale/zh_CN/LC_MESSAGES/swift.po +1 -192
- swift/locale/zh_TW/LC_MESSAGES/swift.po +1 -193
- swift/obj/diskfile.py +19 -6
- swift/obj/server.py +20 -6
- swift/obj/ssync_receiver.py +19 -9
- swift/obj/ssync_sender.py +10 -10
- swift/proxy/controllers/account.py +7 -7
- swift/proxy/controllers/base.py +374 -366
- swift/proxy/controllers/container.py +112 -53
- swift/proxy/controllers/obj.py +254 -390
- swift/proxy/server.py +3 -8
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-server +1 -1
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-server +1 -1
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-drive-audit +45 -14
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-server +1 -1
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-proxy-server +1 -1
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/AUTHORS +4 -0
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/METADATA +32 -35
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/RECORD +103 -100
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/WHEEL +1 -1
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/entry_points.txt +0 -1
- swift-2.32.1.dist-info/pbr.json +1 -0
- swift-2.31.1.dist-info/pbr.json +0 -1
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-audit +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-auditor +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-info +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-reaper +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-account-replicator +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-config +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-auditor +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-info +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-reconciler +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-replicator +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-sharder +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-sync +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-container-updater +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-dispersion-populate +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-dispersion-report +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-form-signature +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-get-nodes +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-init +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-auditor +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-expirer +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-info +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-reconstructor +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-relinker +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-replicator +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-object-updater +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-oldies +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-orphans +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-recon +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-recon-cron +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-reconciler-enqueue +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-ring-builder +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-ring-builder-analyzer +0 -0
- {swift-2.31.1.data → swift-2.32.1.data}/scripts/swift-ring-composer +0 -0
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/LICENSE +0 -0
- {swift-2.31.1.dist-info → swift-2.32.1.dist-info}/top_level.txt +0 -0
@@ -21,13 +21,14 @@ from six.moves.urllib.parse import unquote
|
|
21
21
|
|
22
22
|
from swift.common.memcached import MemcacheConnectionError
|
23
23
|
from swift.common.utils import public, private, csv_append, Timestamp, \
|
24
|
-
config_true_value, ShardRange, cache_from_env,
|
24
|
+
config_true_value, ShardRange, cache_from_env, filter_namespaces, \
|
25
|
+
NamespaceBoundList
|
25
26
|
from swift.common.constraints import check_metadata, CONTAINER_LISTING_LIMIT
|
26
27
|
from swift.common.http import HTTP_ACCEPTED, is_success
|
27
28
|
from swift.common.request_helpers import get_sys_meta_prefix, get_param, \
|
28
29
|
constrain_req_limit, validate_container_params
|
29
|
-
from swift.proxy.controllers.base import Controller, delay_denial, \
|
30
|
-
cors_validation, set_info_cache, clear_info_cache,
|
30
|
+
from swift.proxy.controllers.base import Controller, delay_denial, NodeIter, \
|
31
|
+
cors_validation, set_info_cache, clear_info_cache, get_container_info, \
|
31
32
|
record_cache_op_metrics, get_cache_key, headers_from_container_info, \
|
32
33
|
update_headers
|
33
34
|
from swift.common.storage_policy import POLICIES
|
@@ -91,9 +92,9 @@ class ContainerController(Controller):
|
|
91
92
|
return None
|
92
93
|
|
93
94
|
def _clear_container_info_cache(self, req):
|
94
|
-
clear_info_cache(
|
95
|
+
clear_info_cache(req.environ,
|
95
96
|
self.account_name, self.container_name)
|
96
|
-
clear_info_cache(
|
97
|
+
clear_info_cache(req.environ,
|
97
98
|
self.account_name, self.container_name, 'listing')
|
98
99
|
# TODO: should we also purge updating shards from cache?
|
99
100
|
|
@@ -102,32 +103,49 @@ class ContainerController(Controller):
|
|
102
103
|
self.account_name, self.container_name)
|
103
104
|
concurrency = self.app.container_ring.replica_count \
|
104
105
|
if self.app.get_policy_options(None).concurrent_gets else 1
|
105
|
-
node_iter = self.app
|
106
|
-
|
106
|
+
node_iter = NodeIter(self.app, self.app.container_ring, part,
|
107
|
+
self.logger, req)
|
107
108
|
resp = self.GETorHEAD_base(
|
108
109
|
req, 'Container', node_iter, part,
|
109
110
|
req.swift_entity_path, concurrency)
|
110
111
|
return resp
|
111
112
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
113
|
+
def _make_namespaces_response_body(self, req, ns_bound_list):
|
114
|
+
"""
|
115
|
+
Filter namespaces according to request constraints and return a
|
116
|
+
serialised list of namespaces.
|
117
|
+
|
118
|
+
:param req: the request object.
|
119
|
+
:param ns_bound_list: an instance of
|
120
|
+
:class:`~swift.common.utils.NamespaceBoundList`.
|
121
|
+
:return: a serialised list of namespaces.
|
122
|
+
"""
|
115
123
|
marker = get_param(req, 'marker', '')
|
116
124
|
end_marker = get_param(req, 'end_marker')
|
117
125
|
includes = get_param(req, 'includes')
|
118
126
|
reverse = config_true_value(get_param(req, 'reverse'))
|
119
127
|
if reverse:
|
120
128
|
marker, end_marker = end_marker, marker
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
shard_ranges = filter_shard_ranges(shard_ranges, includes, marker,
|
125
|
-
end_marker)
|
129
|
+
namespaces = ns_bound_list.get_namespaces()
|
130
|
+
namespaces = filter_namespaces(
|
131
|
+
namespaces, includes, marker, end_marker)
|
126
132
|
if reverse:
|
127
|
-
|
128
|
-
return json.dumps([dict(
|
133
|
+
namespaces.reverse()
|
134
|
+
return json.dumps([dict(ns) for ns in namespaces]).encode('ascii')
|
129
135
|
|
130
136
|
def _get_shard_ranges_from_cache(self, req, headers):
|
137
|
+
"""
|
138
|
+
Try to fetch shard namespace data from cache and, if successful, return
|
139
|
+
a response. Also return the cache state.
|
140
|
+
|
141
|
+
The response body will be a list of dicts each of which describes
|
142
|
+
a Namespace (i.e. includes the keys ``lower``, ``upper`` and ``name``).
|
143
|
+
|
144
|
+
:param req: an instance of ``swob.Request``.
|
145
|
+
:param headers: Headers to be sent with request.
|
146
|
+
:return: a tuple comprising (an instance of ``swob.Response``or
|
147
|
+
``None`` if no namespaces were found in cache, the cache state).
|
148
|
+
"""
|
131
149
|
infocache = req.environ.setdefault('swift.infocache', {})
|
132
150
|
memcache = cache_from_env(req.environ, True)
|
133
151
|
cache_key = get_cache_key(self.account_name,
|
@@ -135,11 +153,10 @@ class ContainerController(Controller):
|
|
135
153
|
shard='listing')
|
136
154
|
|
137
155
|
resp_body = None
|
138
|
-
|
139
|
-
if
|
156
|
+
ns_bound_list = infocache.get(cache_key)
|
157
|
+
if ns_bound_list:
|
140
158
|
cache_state = 'infocache_hit'
|
141
|
-
resp_body = self.
|
142
|
-
req, cached_range_dicts)
|
159
|
+
resp_body = self._make_namespaces_response_body(req, ns_bound_list)
|
143
160
|
elif memcache:
|
144
161
|
skip_chance = \
|
145
162
|
self.app.container_listing_shard_ranges_skip_cache
|
@@ -147,12 +164,20 @@ class ContainerController(Controller):
|
|
147
164
|
cache_state = 'skip'
|
148
165
|
else:
|
149
166
|
try:
|
150
|
-
|
167
|
+
cached_namespaces = memcache.get(
|
151
168
|
cache_key, raise_on_error=True)
|
152
|
-
if
|
169
|
+
if cached_namespaces:
|
153
170
|
cache_state = 'hit'
|
154
|
-
|
155
|
-
|
171
|
+
if six.PY2:
|
172
|
+
# json.loads() in memcache.get will convert json
|
173
|
+
# 'string' to 'unicode' with python2, here we cast
|
174
|
+
# 'unicode' back to 'str'
|
175
|
+
cached_namespaces = [
|
176
|
+
[lower.encode('utf-8'), name.encode('utf-8')]
|
177
|
+
for lower, name in cached_namespaces]
|
178
|
+
ns_bound_list = NamespaceBoundList(cached_namespaces)
|
179
|
+
resp_body = self._make_namespaces_response_body(
|
180
|
+
req, ns_bound_list)
|
156
181
|
else:
|
157
182
|
cache_state = 'miss'
|
158
183
|
except MemcacheConnectionError:
|
@@ -162,9 +187,9 @@ class ContainerController(Controller):
|
|
162
187
|
resp = None
|
163
188
|
else:
|
164
189
|
# shard ranges can be returned from cache
|
165
|
-
infocache[cache_key] =
|
190
|
+
infocache[cache_key] = ns_bound_list
|
166
191
|
self.logger.debug('Found %d shards in cache for %s',
|
167
|
-
len(
|
192
|
+
len(ns_bound_list.bounds), req.path_qs)
|
168
193
|
headers.update({'x-backend-record-type': 'shard',
|
169
194
|
'x-backend-cached-results': 'true'})
|
170
195
|
# mimic GetOrHeadHandler.get_working_response...
|
@@ -180,36 +205,62 @@ class ContainerController(Controller):
|
|
180
205
|
return resp, cache_state
|
181
206
|
|
182
207
|
def _store_shard_ranges_in_cache(self, req, resp):
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
208
|
+
"""
|
209
|
+
Parse shard ranges returned from backend, store them in both infocache
|
210
|
+
and memcache.
|
211
|
+
|
212
|
+
:param req: the request object.
|
213
|
+
:param resp: the response object for the shard range listing.
|
214
|
+
:return: an instance of
|
215
|
+
:class:`~swift.common.utils.NamespaceBoundList`.
|
216
|
+
"""
|
217
|
+
# Note: Any gaps in the response's shard ranges will be 'lost' as a
|
218
|
+
# result of compacting the list of shard ranges to a
|
219
|
+
# NamespaceBoundList. That is ok. When the cached NamespaceBoundList is
|
220
|
+
# transformed back to shard range Namespaces to perform a listing, the
|
221
|
+
# Namespace before each gap will have expanded to include the gap,
|
222
|
+
# which means that the backend GET to that shard will have an
|
223
|
+
# end_marker beyond that shard's upper bound, and equal to the next
|
224
|
+
# available shard's lower. At worst, some misplaced objects, in the gap
|
225
|
+
# above the shard's upper, may be included in the shard's response.
|
187
226
|
data = self._parse_listing_response(req, resp)
|
188
227
|
backend_shard_ranges = self._parse_shard_ranges(req, data, resp)
|
189
228
|
if backend_shard_ranges is None:
|
190
229
|
return None
|
191
230
|
|
192
|
-
|
231
|
+
ns_bound_list = NamespaceBoundList.parse(backend_shard_ranges)
|
193
232
|
if resp.headers.get('x-backend-sharding-state') == 'sharded':
|
194
233
|
# cache in infocache even if no shard ranges returned; this
|
195
234
|
# is unexpected but use that result for this request
|
196
235
|
infocache = req.environ.setdefault('swift.infocache', {})
|
197
|
-
|
236
|
+
cache_key = get_cache_key(
|
237
|
+
self.account_name, self.container_name, shard='listing')
|
238
|
+
infocache[cache_key] = ns_bound_list
|
198
239
|
memcache = cache_from_env(req.environ, True)
|
199
|
-
if memcache and
|
240
|
+
if memcache and ns_bound_list:
|
200
241
|
# cache in memcache only if shard ranges as expected
|
201
|
-
self.logger.
|
202
|
-
|
203
|
-
memcache.set(cache_key,
|
242
|
+
self.logger.info('Caching listing shards for %s (%d shards)',
|
243
|
+
cache_key, len(ns_bound_list.bounds))
|
244
|
+
memcache.set(cache_key, ns_bound_list.bounds,
|
204
245
|
time=self.app.recheck_listing_shard_ranges)
|
205
|
-
return
|
246
|
+
return ns_bound_list
|
206
247
|
|
207
248
|
def _get_shard_ranges_from_backend(self, req):
|
208
|
-
|
209
|
-
|
249
|
+
"""
|
250
|
+
Make a backend request for shard ranges and return a response.
|
251
|
+
|
252
|
+
The response body will be a list of dicts each of which describes
|
253
|
+
a Namespace (i.e. includes the keys ``lower``, ``upper`` and ``name``).
|
254
|
+
If the response headers indicate that the response body contains a
|
255
|
+
complete list of shard ranges for a sharded container then the response
|
256
|
+
body will be transformed to a ``NamespaceBoundsList`` and cached.
|
257
|
+
|
258
|
+
:param req: an instance of ``swob.Request``.
|
259
|
+
:return: an instance of ``swob.Response``.
|
260
|
+
"""
|
210
261
|
# Note: We instruct the backend server to ignore name constraints in
|
211
262
|
# request params if returning shard ranges so that the response can
|
212
|
-
# potentially be cached
|
263
|
+
# potentially be cached, but we only cache it if the container state is
|
213
264
|
# 'sharded'. We don't attempt to cache shard ranges for a 'sharding'
|
214
265
|
# container as they may include the container itself as a 'gap filler'
|
215
266
|
# for shard ranges that have not yet cleaved; listings from 'gap
|
@@ -232,10 +283,10 @@ class ContainerController(Controller):
|
|
232
283
|
if (resp_record_type == 'shard' and
|
233
284
|
sharding_state == 'sharded' and
|
234
285
|
complete_listing):
|
235
|
-
|
236
|
-
if
|
237
|
-
resp.body = self.
|
238
|
-
req,
|
286
|
+
ns_bound_list = self._store_shard_ranges_in_cache(req, resp)
|
287
|
+
if ns_bound_list:
|
288
|
+
resp.body = self._make_namespaces_response_body(
|
289
|
+
req, ns_bound_list)
|
239
290
|
return resp
|
240
291
|
|
241
292
|
def _record_shard_listing_cache_metrics(
|
@@ -334,18 +385,19 @@ class ContainerController(Controller):
|
|
334
385
|
params['states'] = 'listing'
|
335
386
|
req.params = params
|
336
387
|
|
337
|
-
memcache = cache_from_env(req.environ, True)
|
338
388
|
if (req.method == 'GET'
|
339
389
|
and get_param(req, 'states') == 'listing'
|
340
390
|
and record_type != 'object'):
|
341
391
|
may_get_listing_shards = True
|
342
|
-
info
|
343
|
-
|
344
|
-
|
392
|
+
# Only lookup container info from cache and skip the backend HEAD,
|
393
|
+
# since we are going to GET the backend container anyway.
|
394
|
+
info = get_container_info(
|
395
|
+
req.environ, self.app, swift_source=None, cache_only=True)
|
345
396
|
else:
|
346
397
|
info = None
|
347
398
|
may_get_listing_shards = False
|
348
399
|
|
400
|
+
memcache = cache_from_env(req.environ, True)
|
349
401
|
sr_cache_state = None
|
350
402
|
if (may_get_listing_shards and
|
351
403
|
self.app.recheck_listing_shard_ranges > 0
|
@@ -379,10 +431,10 @@ class ContainerController(Controller):
|
|
379
431
|
# node and got up-to-date information for the container.
|
380
432
|
resp.headers['X-Backend-Recheck-Container-Existence'] = str(
|
381
433
|
self.app.recheck_container_existence)
|
382
|
-
set_info_cache(
|
434
|
+
set_info_cache(req.environ, self.account_name,
|
383
435
|
self.container_name, resp)
|
384
436
|
if 'swift.authorize' in req.environ:
|
385
|
-
req.acl = resp.headers.get('x-container-read')
|
437
|
+
req.acl = wsgi_to_str(resp.headers.get('x-container-read'))
|
386
438
|
aresp = req.environ['swift.authorize'](req)
|
387
439
|
if aresp:
|
388
440
|
# Don't cache this. It doesn't reflect the state of the
|
@@ -424,8 +476,15 @@ class ContainerController(Controller):
|
|
424
476
|
# 'X-Backend-Storage-Policy-Index'.
|
425
477
|
req.headers[policy_key] = resp.headers[policy_key]
|
426
478
|
shard_listing_history.append((self.account_name, self.container_name))
|
427
|
-
|
428
|
-
|
479
|
+
# Note: when the response body has been synthesised from cached data,
|
480
|
+
# each item in the list only has 'name', 'lower' and 'upper' keys. We
|
481
|
+
# therefore cannot use ShardRange.from_dict(), and the ShardRange
|
482
|
+
# instances constructed here will only have 'name', 'lower' and 'upper'
|
483
|
+
# attributes set.
|
484
|
+
# Ideally we would construct Namespace objects here, but later we use
|
485
|
+
# the ShardRange account and container properties to access parsed
|
486
|
+
# parts of the name.
|
487
|
+
shard_ranges = [ShardRange(**data) for data in json.loads(resp.body)]
|
429
488
|
self.logger.debug('GET listing from %s shards for: %s',
|
430
489
|
len(shard_ranges), req.path_qs)
|
431
490
|
if not shard_ranges:
|