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/container/sync.py
CHANGED
@@ -17,84 +17,59 @@ import collections
|
|
17
17
|
import errno
|
18
18
|
import os
|
19
19
|
import uuid
|
20
|
-
from swift import gettext_ as _
|
21
20
|
from time import ctime, time
|
22
21
|
from random import choice, random
|
23
22
|
from struct import unpack_from
|
24
23
|
|
25
24
|
from eventlet import sleep, Timeout
|
26
|
-
from
|
25
|
+
from urllib.parse import urlparse
|
27
26
|
|
28
27
|
import swift.common.db
|
29
28
|
from swift.common.db import DatabaseConnectionError
|
30
29
|
from swift.container.backend import ContainerBroker
|
31
30
|
from swift.container.sync_store import ContainerSyncStore
|
32
31
|
from swift.common.container_sync_realms import ContainerSyncRealms
|
32
|
+
from swift.common.daemon import run_daemon
|
33
33
|
from swift.common.internal_client import (
|
34
34
|
delete_object, put_object, head_object,
|
35
35
|
InternalClient, UnexpectedResponse)
|
36
36
|
from swift.common.exceptions import ClientException
|
37
37
|
from swift.common.ring import Ring
|
38
38
|
from swift.common.ring.utils import is_local_device
|
39
|
+
from swift.common.swob import normalize_etag
|
39
40
|
from swift.common.utils import (
|
40
41
|
clean_content_type, config_true_value,
|
41
42
|
FileLikeIter, get_logger, hash_path, quote, validate_sync_to,
|
42
|
-
whataremyips, Timestamp, decode_timestamps)
|
43
|
+
whataremyips, Timestamp, decode_timestamps, parse_options)
|
43
44
|
from swift.common.daemon import Daemon
|
44
|
-
from swift.common.http import HTTP_UNAUTHORIZED, HTTP_NOT_FOUND
|
45
|
+
from swift.common.http import HTTP_UNAUTHORIZED, HTTP_NOT_FOUND, HTTP_CONFLICT
|
45
46
|
from swift.common.wsgi import ConfigString
|
47
|
+
from swift.common.middleware.versioned_writes.object_versioning import (
|
48
|
+
SYSMETA_VERSIONS_CONT, SYSMETA_VERSIONS_SYMLINK)
|
46
49
|
|
47
50
|
|
48
51
|
# The default internal client config body is to support upgrades without
|
49
52
|
# requiring deployment of the new /etc/swift/internal-client.conf
|
50
53
|
ic_conf_body = """
|
51
54
|
[DEFAULT]
|
52
|
-
# swift_dir = /etc/swift
|
53
|
-
# user = swift
|
54
|
-
# You can specify default log routing here if you want:
|
55
|
-
# log_name = swift
|
56
|
-
# log_facility = LOG_LOCAL0
|
57
|
-
# log_level = INFO
|
58
|
-
# log_address = /dev/log
|
59
|
-
#
|
60
|
-
# comma separated list of functions to call to setup custom log handlers.
|
61
|
-
# functions get passed: conf, name, log_to_console, log_route, fmt, logger,
|
62
|
-
# adapted_logger
|
63
|
-
# log_custom_handlers =
|
64
|
-
#
|
65
|
-
# If set, log_udp_host will override log_address
|
66
|
-
# log_udp_host =
|
67
|
-
# log_udp_port = 514
|
68
|
-
#
|
69
|
-
# You can enable StatsD logging here:
|
70
|
-
# log_statsd_host =
|
71
|
-
# log_statsd_port = 8125
|
72
|
-
# log_statsd_default_sample_rate = 1.0
|
73
|
-
# log_statsd_sample_rate_factor = 1.0
|
74
|
-
# log_statsd_metric_prefix =
|
75
|
-
|
76
55
|
[pipeline:main]
|
77
56
|
pipeline = catch_errors proxy-logging cache symlink proxy-server
|
78
57
|
|
79
58
|
[app:proxy-server]
|
80
59
|
use = egg:swift#proxy
|
81
60
|
account_autocreate = true
|
82
|
-
# See proxy-server.conf-sample for options
|
83
61
|
|
84
62
|
[filter:symlink]
|
85
63
|
use = egg:swift#symlink
|
86
|
-
# See proxy-server.conf-sample for options
|
87
64
|
|
88
65
|
[filter:cache]
|
89
66
|
use = egg:swift#memcache
|
90
|
-
# See proxy-server.conf-sample for options
|
91
67
|
|
92
68
|
[filter:proxy-logging]
|
93
69
|
use = egg:swift#proxy_logging
|
94
70
|
|
95
71
|
[filter:catch_errors]
|
96
72
|
use = egg:swift#catch_errors
|
97
|
-
# See proxy-server.conf-sample for options
|
98
73
|
""".lstrip()
|
99
74
|
|
100
75
|
|
@@ -122,28 +97,28 @@ class ContainerSync(Daemon):
|
|
122
97
|
An example may help. Assume replica count is 3 and perfectly matching
|
123
98
|
ROWIDs starting at 1.
|
124
99
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
100
|
+
First sync run, database has 6 rows:
|
101
|
+
|
102
|
+
* SyncPoint1 starts as -1.
|
103
|
+
* SyncPoint2 starts as -1.
|
104
|
+
* No rows between points, so no "all updates" rows.
|
105
|
+
* Six rows newer than SyncPoint1, so a third of the rows are sent
|
106
|
+
by node 1, another third by node 2, remaining third by node 3.
|
107
|
+
* SyncPoint1 is set as 6 (the newest ROWID known).
|
108
|
+
* SyncPoint2 is left as -1 since no "all updates" rows were synced.
|
109
|
+
|
110
|
+
Next sync run, database has 12 rows:
|
111
|
+
|
112
|
+
* SyncPoint1 starts as 6.
|
113
|
+
* SyncPoint2 starts as -1.
|
114
|
+
* The rows between -1 and 6 all trigger updates (most of which
|
115
|
+
should short-circuit on the remote end as having already been
|
116
|
+
done).
|
117
|
+
* Six more rows newer than SyncPoint1, so a third of the rows are
|
118
|
+
sent by node 1, another third by node 2, remaining third by node
|
119
|
+
3.
|
120
|
+
* SyncPoint1 is set as 12 (the newest ROWID known).
|
121
|
+
* SyncPoint2 is set as 6 (the newest "all updates" ROWID).
|
147
122
|
|
148
123
|
In this way, under normal circumstances each node sends its share of
|
149
124
|
updates each run and just sends a batch of older updates to ensure nothing
|
@@ -154,13 +129,14 @@ class ContainerSync(Daemon):
|
|
154
129
|
:param container_ring: If None, the <swift_dir>/container.ring.gz will be
|
155
130
|
loaded. This is overridden by unit tests.
|
156
131
|
"""
|
132
|
+
log_route = 'container-sync'
|
157
133
|
|
158
134
|
def __init__(self, conf, container_ring=None, logger=None):
|
159
135
|
#: The dict of configuration values from the [container-sync] section
|
160
136
|
#: of the container-server.conf.
|
161
137
|
self.conf = conf
|
162
138
|
#: Logger to use for container-sync log lines.
|
163
|
-
self.logger = logger or get_logger(conf, log_route=
|
139
|
+
self.logger = logger or get_logger(conf, log_route=self.log_route)
|
164
140
|
#: Path to the local device mount points.
|
165
141
|
self.devices = conf.get('devices', '/srv/node')
|
166
142
|
#: Indicates whether mount points should be verified as actual mount
|
@@ -168,7 +144,7 @@ class ContainerSync(Daemon):
|
|
168
144
|
self.mount_check = config_true_value(conf.get('mount_check', 'true'))
|
169
145
|
#: Minimum time between full scans. This is to keep the daemon from
|
170
146
|
#: running wild on near empty systems.
|
171
|
-
self.interval =
|
147
|
+
self.interval = float(conf.get('interval', 300))
|
172
148
|
#: Maximum amount of time to spend syncing a container before moving on
|
173
149
|
#: to the next one. If a container sync hasn't finished in this time,
|
174
150
|
#: it'll just be resumed next scan.
|
@@ -230,22 +206,25 @@ class ContainerSync(Daemon):
|
|
230
206
|
internal_client_conf_path = conf.get('internal_client_conf_path')
|
231
207
|
if not internal_client_conf_path:
|
232
208
|
self.logger.warning(
|
233
|
-
|
234
|
-
|
235
|
-
|
209
|
+
'Configuration option internal_client_conf_path not '
|
210
|
+
'defined. Using default configuration, See '
|
211
|
+
'internal-client.conf-sample for options')
|
236
212
|
internal_client_conf = ConfigString(ic_conf_body)
|
237
213
|
else:
|
238
214
|
internal_client_conf = internal_client_conf_path
|
239
215
|
try:
|
240
216
|
self.swift = InternalClient(
|
241
|
-
internal_client_conf, 'Swift Container Sync', request_tries
|
217
|
+
internal_client_conf, 'Swift Container Sync', request_tries,
|
218
|
+
use_replication_network=True,
|
219
|
+
global_conf={'log_name': '%s-ic' % conf.get(
|
220
|
+
'log_name', self.log_route)})
|
242
221
|
except (OSError, IOError) as err:
|
243
222
|
if err.errno != errno.ENOENT and \
|
244
223
|
not str(err).endswith(' not found'):
|
245
224
|
raise
|
246
225
|
raise SystemExit(
|
247
|
-
|
248
|
-
|
226
|
+
'Unable to load internal client from config: '
|
227
|
+
'%(conf)r (%(error)s)'
|
249
228
|
% {'conf': internal_client_conf_path, 'error': err})
|
250
229
|
|
251
230
|
def run_forever(self, *args, **kwargs):
|
@@ -268,7 +247,7 @@ class ContainerSync(Daemon):
|
|
268
247
|
"""
|
269
248
|
Runs a single container sync scan.
|
270
249
|
"""
|
271
|
-
self.logger.info(
|
250
|
+
self.logger.info('Begin container sync "once" mode')
|
272
251
|
begin = time()
|
273
252
|
for path in self.sync_store.synced_containers_generator():
|
274
253
|
self.container_sync(path)
|
@@ -277,7 +256,7 @@ class ContainerSync(Daemon):
|
|
277
256
|
self.report()
|
278
257
|
elapsed = time() - begin
|
279
258
|
self.logger.info(
|
280
|
-
|
259
|
+
'Container sync "once" mode completed: %.02fs', elapsed)
|
281
260
|
|
282
261
|
def report(self):
|
283
262
|
"""
|
@@ -285,8 +264,8 @@ class ContainerSync(Daemon):
|
|
285
264
|
next report.
|
286
265
|
"""
|
287
266
|
self.logger.info(
|
288
|
-
|
289
|
-
|
267
|
+
'Since %(time)s: %(sync)s synced [%(delete)s deletes, %(put)s '
|
268
|
+
'puts], %(skip)s skipped, %(fail)s failed',
|
290
269
|
{'time': ctime(self.reported),
|
291
270
|
'sync': self.container_syncs,
|
292
271
|
'delete': self.container_deletes,
|
@@ -302,16 +281,16 @@ class ContainerSync(Daemon):
|
|
302
281
|
|
303
282
|
def container_report(self, start, end, sync_point1, sync_point2, info,
|
304
283
|
max_row):
|
305
|
-
self.logger.info(
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
284
|
+
self.logger.info('Container sync report: %(container)s, '
|
285
|
+
'time window start: %(start)s, '
|
286
|
+
'time window end: %(end)s, '
|
287
|
+
'puts: %(puts)s, '
|
288
|
+
'posts: %(posts)s, '
|
289
|
+
'deletes: %(deletes)s, '
|
290
|
+
'bytes: %(bytes)s, '
|
291
|
+
'sync_point1: %(point1)s, '
|
292
|
+
'sync_point2: %(point2)s, '
|
293
|
+
'total_rows: %(total)s',
|
315
294
|
{'container': '%s/%s' % (info['account'],
|
316
295
|
info['container']),
|
317
296
|
'start': start,
|
@@ -357,6 +336,13 @@ class ContainerSync(Daemon):
|
|
357
336
|
break
|
358
337
|
else:
|
359
338
|
return
|
339
|
+
if broker.metadata.get(SYSMETA_VERSIONS_CONT):
|
340
|
+
self.container_skips += 1
|
341
|
+
self.logger.increment('skips')
|
342
|
+
self.logger.warning('Skipping container %s/%s with '
|
343
|
+
'object versioning configured' % (
|
344
|
+
info['account'], info['container']))
|
345
|
+
return
|
360
346
|
if not broker.is_deleted():
|
361
347
|
sync_to = None
|
362
348
|
user_key = None
|
@@ -375,7 +361,7 @@ class ContainerSync(Daemon):
|
|
375
361
|
sync_to, self.allowed_sync_hosts, self.realms_conf)
|
376
362
|
if err:
|
377
363
|
self.logger.info(
|
378
|
-
|
364
|
+
'ERROR %(db_file)s: %(validate_sync_to_err)s',
|
379
365
|
{'db_file': str(broker),
|
380
366
|
'validate_sync_to_err': err})
|
381
367
|
self.container_failures += 1
|
@@ -444,7 +430,7 @@ class ContainerSync(Daemon):
|
|
444
430
|
except (Exception, Timeout):
|
445
431
|
self.container_failures += 1
|
446
432
|
self.logger.increment('failures')
|
447
|
-
self.logger.exception(
|
433
|
+
self.logger.exception('ERROR Syncing %s',
|
448
434
|
broker if broker else path)
|
449
435
|
|
450
436
|
def _update_sync_to_headers(self, name, sync_to, user_key,
|
@@ -560,7 +546,8 @@ class ContainerSync(Daemon):
|
|
560
546
|
logger=self.logger,
|
561
547
|
timeout=self.conn_timeout)
|
562
548
|
except ClientException as err:
|
563
|
-
if err.http_status
|
549
|
+
if err.http_status not in (
|
550
|
+
HTTP_NOT_FOUND, HTTP_CONFLICT):
|
564
551
|
raise
|
565
552
|
self.container_deletes += 1
|
566
553
|
self.container_stats['deletes'] += 1
|
@@ -593,13 +580,23 @@ class ContainerSync(Daemon):
|
|
593
580
|
headers = {}
|
594
581
|
body = None
|
595
582
|
exc = err
|
583
|
+
|
584
|
+
# skip object_versioning links; this is in case the container
|
585
|
+
# metadata is out of date
|
586
|
+
if headers.get(SYSMETA_VERSIONS_SYMLINK):
|
587
|
+
self.logger.info(
|
588
|
+
'Skipping versioning symlink %s/%s/%s ' % (
|
589
|
+
info['account'], info['container'],
|
590
|
+
row['name']))
|
591
|
+
return True
|
592
|
+
|
596
593
|
timestamp = Timestamp(headers.get('x-timestamp', 0))
|
597
594
|
if timestamp < ts_meta:
|
598
595
|
if exc:
|
599
596
|
raise exc
|
600
597
|
raise Exception(
|
601
|
-
|
602
|
-
|
598
|
+
'Unknown exception trying to GET: '
|
599
|
+
'%(account)r %(container)r %(object)r' %
|
603
600
|
{'account': info['account'],
|
604
601
|
'container': info['container'],
|
605
602
|
'object': row['name']})
|
@@ -607,7 +604,7 @@ class ContainerSync(Daemon):
|
|
607
604
|
if key in headers:
|
608
605
|
del headers[key]
|
609
606
|
if 'etag' in headers:
|
610
|
-
headers['etag'] = headers['etag']
|
607
|
+
headers['etag'] = normalize_etag(headers['etag'])
|
611
608
|
if 'content-type' in headers:
|
612
609
|
headers['content-type'] = clean_content_type(
|
613
610
|
headers['content-type'])
|
@@ -625,27 +622,27 @@ class ContainerSync(Daemon):
|
|
625
622
|
except ClientException as err:
|
626
623
|
if err.http_status == HTTP_UNAUTHORIZED:
|
627
624
|
self.logger.info(
|
628
|
-
|
625
|
+
'Unauth %(sync_from)r => %(sync_to)r',
|
629
626
|
{'sync_from': '%s/%s' %
|
630
627
|
(quote(info['account']), quote(info['container'])),
|
631
628
|
'sync_to': sync_to})
|
632
629
|
elif err.http_status == HTTP_NOT_FOUND:
|
633
630
|
self.logger.info(
|
634
|
-
|
635
|
-
|
631
|
+
'Not found %(sync_from)r => %(sync_to)r \
|
632
|
+
- object %(obj_name)r',
|
636
633
|
{'sync_from': '%s/%s' %
|
637
634
|
(quote(info['account']), quote(info['container'])),
|
638
635
|
'sync_to': sync_to, 'obj_name': row['name']})
|
639
636
|
else:
|
640
637
|
self.logger.exception(
|
641
|
-
|
638
|
+
'ERROR Syncing %(db_file)s %(row)s',
|
642
639
|
{'db_file': str(broker), 'row': row})
|
643
640
|
self.container_failures += 1
|
644
641
|
self.logger.increment('failures')
|
645
642
|
return False
|
646
|
-
except (Exception, Timeout)
|
643
|
+
except (Exception, Timeout):
|
647
644
|
self.logger.exception(
|
648
|
-
|
645
|
+
'ERROR Syncing %(db_file)s %(row)s',
|
649
646
|
{'db_file': str(broker), 'row': row})
|
650
647
|
self.container_failures += 1
|
651
648
|
self.logger.increment('failures')
|
@@ -654,3 +651,12 @@ class ContainerSync(Daemon):
|
|
654
651
|
|
655
652
|
def select_http_proxy(self):
|
656
653
|
return choice(self.http_proxies) if self.http_proxies else None
|
654
|
+
|
655
|
+
|
656
|
+
def main():
|
657
|
+
conf_file, options = parse_options(once=True)
|
658
|
+
run_daemon(ContainerSync, conf_file, **options)
|
659
|
+
|
660
|
+
|
661
|
+
if __name__ == '__main__':
|
662
|
+
main()
|
swift/container/updater.py
CHANGED
@@ -13,13 +13,11 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
|
16
|
-
from __future__ import print_function
|
17
16
|
import logging
|
18
17
|
import os
|
19
18
|
import signal
|
20
19
|
import sys
|
21
20
|
import time
|
22
|
-
from swift import gettext_ as _
|
23
21
|
from random import random, shuffle
|
24
22
|
from tempfile import mkstemp
|
25
23
|
|
@@ -32,10 +30,11 @@ from swift.common.bufferedhttp import http_connect
|
|
32
30
|
from swift.common.exceptions import ConnectionTimeout, LockTimeout
|
33
31
|
from swift.common.ring import Ring
|
34
32
|
from swift.common.utils import get_logger, config_true_value, \
|
35
|
-
dump_recon_cache, majority_size, Timestamp,
|
36
|
-
eventlet_monkey_patch
|
37
|
-
from swift.common.daemon import Daemon
|
33
|
+
dump_recon_cache, majority_size, Timestamp, EventletRateLimiter, \
|
34
|
+
eventlet_monkey_patch, node_to_string, parse_options
|
35
|
+
from swift.common.daemon import Daemon, run_daemon
|
38
36
|
from swift.common.http import is_success, HTTP_INTERNAL_SERVER_ERROR
|
37
|
+
from swift.common.recon import RECON_CONTAINER_FILE, DEFAULT_RECON_CACHE_PATH
|
39
38
|
|
40
39
|
|
41
40
|
class ContainerUpdater(Daemon):
|
@@ -47,7 +46,7 @@ class ContainerUpdater(Daemon):
|
|
47
46
|
self.devices = conf.get('devices', '/srv/node')
|
48
47
|
self.mount_check = config_true_value(conf.get('mount_check', 'true'))
|
49
48
|
self.swift_dir = conf.get('swift_dir', '/etc/swift')
|
50
|
-
self.interval =
|
49
|
+
self.interval = float(conf.get('interval', 300))
|
51
50
|
self.account_ring = None
|
52
51
|
self.concurrency = int(conf.get('concurrency', 4))
|
53
52
|
if 'slowdown' in conf:
|
@@ -59,10 +58,10 @@ class ContainerUpdater(Daemon):
|
|
59
58
|
float(conf.get('slowdown', '0.01')) + 0.01)
|
60
59
|
else:
|
61
60
|
containers_per_second = 50
|
62
|
-
self.containers_running_time = 0
|
63
61
|
self.max_containers_per_second = \
|
64
62
|
float(conf.get('containers_per_second',
|
65
63
|
containers_per_second))
|
64
|
+
self.rate_limiter = EventletRateLimiter(self.max_containers_per_second)
|
66
65
|
self.node_timeout = float(conf.get('node_timeout', 3))
|
67
66
|
self.conn_timeout = float(conf.get('conn_timeout', 0.5))
|
68
67
|
self.no_changes = 0
|
@@ -75,8 +74,8 @@ class ContainerUpdater(Daemon):
|
|
75
74
|
swift.common.db.DB_PREALLOCATION = \
|
76
75
|
config_true_value(conf.get('db_preallocation', 'f'))
|
77
76
|
self.recon_cache_path = conf.get('recon_cache_path',
|
78
|
-
|
79
|
-
self.rcache = os.path.join(self.recon_cache_path,
|
77
|
+
DEFAULT_RECON_CACHE_PATH)
|
78
|
+
self.rcache = os.path.join(self.recon_cache_path, RECON_CONTAINER_FILE)
|
80
79
|
self.user_agent = 'container-updater %s' % os.getpid()
|
81
80
|
|
82
81
|
def get_account_ring(self):
|
@@ -89,8 +88,8 @@ class ContainerUpdater(Daemon):
|
|
89
88
|
try:
|
90
89
|
return os.listdir(path)
|
91
90
|
except OSError as e:
|
92
|
-
self.logger.error(
|
93
|
-
|
91
|
+
self.logger.error('ERROR: Failed to get paths to drive '
|
92
|
+
'partitions: %s', e)
|
94
93
|
return []
|
95
94
|
|
96
95
|
def get_paths(self):
|
@@ -123,7 +122,7 @@ class ContainerUpdater(Daemon):
|
|
123
122
|
self.account_suppressions[account] = until
|
124
123
|
except Exception:
|
125
124
|
self.logger.exception(
|
126
|
-
|
125
|
+
'ERROR with loading suppressions from %s: ', filename)
|
127
126
|
finally:
|
128
127
|
os.unlink(filename)
|
129
128
|
|
@@ -133,7 +132,7 @@ class ContainerUpdater(Daemon):
|
|
133
132
|
"""
|
134
133
|
time.sleep(random() * self.interval)
|
135
134
|
while True:
|
136
|
-
self.logger.info(
|
135
|
+
self.logger.info('Begin container update sweep')
|
137
136
|
begin = time.time()
|
138
137
|
now = time.time()
|
139
138
|
expired_suppressions = \
|
@@ -158,6 +157,7 @@ class ContainerUpdater(Daemon):
|
|
158
157
|
pid2filename[pid] = tmpfilename
|
159
158
|
else:
|
160
159
|
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
160
|
+
os.environ.pop('NOTIFY_SOCKET', None)
|
161
161
|
eventlet_monkey_patch()
|
162
162
|
self.no_changes = 0
|
163
163
|
self.successes = 0
|
@@ -167,9 +167,9 @@ class ContainerUpdater(Daemon):
|
|
167
167
|
self.container_sweep(path)
|
168
168
|
elapsed = time.time() - forkbegin
|
169
169
|
self.logger.debug(
|
170
|
-
|
171
|
-
|
172
|
-
|
170
|
+
'Container update sweep of %(path)s completed: '
|
171
|
+
'%(elapsed).02fs, %(success)s successes, %(fail)s '
|
172
|
+
'failures, %(no_change)s with no changes',
|
173
173
|
{'path': path, 'elapsed': elapsed,
|
174
174
|
'success': self.successes, 'fail': self.failures,
|
175
175
|
'no_change': self.no_changes})
|
@@ -181,7 +181,7 @@ class ContainerUpdater(Daemon):
|
|
181
181
|
finally:
|
182
182
|
del pid2filename[pid]
|
183
183
|
elapsed = time.time() - begin
|
184
|
-
self.logger.info(
|
184
|
+
self.logger.info('Container update sweep completed: %.02fs',
|
185
185
|
elapsed)
|
186
186
|
dump_recon_cache({'container_updater_sweep': elapsed},
|
187
187
|
self.rcache, self.logger)
|
@@ -193,7 +193,7 @@ class ContainerUpdater(Daemon):
|
|
193
193
|
Run the updater once.
|
194
194
|
"""
|
195
195
|
eventlet_monkey_patch()
|
196
|
-
self.logger.info(
|
196
|
+
self.logger.info('Begin container update single threaded sweep')
|
197
197
|
begin = time.time()
|
198
198
|
self.no_changes = 0
|
199
199
|
self.successes = 0
|
@@ -201,10 +201,10 @@ class ContainerUpdater(Daemon):
|
|
201
201
|
for path in self.get_paths():
|
202
202
|
self.container_sweep(path)
|
203
203
|
elapsed = time.time() - begin
|
204
|
-
self.logger.info(
|
204
|
+
self.logger.info(
|
205
205
|
'Container update single threaded sweep completed: '
|
206
206
|
'%(elapsed).02fs, %(success)s successes, %(fail)s failures, '
|
207
|
-
'%(no_change)s with no changes'
|
207
|
+
'%(no_change)s with no changes',
|
208
208
|
{'elapsed': elapsed, 'success': self.successes,
|
209
209
|
'fail': self.failures, 'no_change': self.no_changes})
|
210
210
|
dump_recon_cache({'container_updater_sweep': elapsed},
|
@@ -226,9 +226,7 @@ class ContainerUpdater(Daemon):
|
|
226
226
|
self.logger.exception(
|
227
227
|
"Error processing container %s: %s", dbfile, e)
|
228
228
|
|
229
|
-
self.
|
230
|
-
self.containers_running_time,
|
231
|
-
self.max_containers_per_second)
|
229
|
+
self.rate_limiter.wait()
|
232
230
|
|
233
231
|
def process_container(self, dbfile):
|
234
232
|
"""
|
@@ -270,23 +268,36 @@ class ContainerUpdater(Daemon):
|
|
270
268
|
info['storage_policy_index'])
|
271
269
|
for node in nodes]
|
272
270
|
successes = 0
|
271
|
+
stub404s = 0
|
273
272
|
for event in events:
|
274
|
-
|
273
|
+
result = event.wait()
|
274
|
+
if is_success(result):
|
275
275
|
successes += 1
|
276
|
+
if result == 404:
|
277
|
+
stub404s += 1
|
276
278
|
if successes >= majority_size(len(events)):
|
277
279
|
self.logger.increment('successes')
|
278
280
|
self.successes += 1
|
279
281
|
self.logger.debug(
|
280
|
-
|
282
|
+
'Update report sent for %(container)s %(dbfile)s',
|
281
283
|
{'container': container, 'dbfile': dbfile})
|
282
284
|
broker.reported(info['put_timestamp'],
|
283
285
|
info['delete_timestamp'], info['object_count'],
|
284
286
|
info['bytes_used'])
|
287
|
+
elif stub404s == len(events):
|
288
|
+
self.logger.increment('failures')
|
289
|
+
self.failures += 1
|
290
|
+
self.logger.debug(
|
291
|
+
'Update report stub for %(container)s %(dbfile)s',
|
292
|
+
{'container': container, 'dbfile': dbfile})
|
293
|
+
broker.quarantine('no account replicas exist')
|
294
|
+
# All that's left at this point is a few sacks of Gnocchi,
|
295
|
+
# easily collected by the dark data watcher in object auditor.
|
285
296
|
else:
|
286
297
|
self.logger.increment('failures')
|
287
298
|
self.failures += 1
|
288
299
|
self.logger.debug(
|
289
|
-
|
300
|
+
'Update report failed for %(container)s %(dbfile)s',
|
290
301
|
{'container': container, 'dbfile': dbfile})
|
291
302
|
self.account_suppressions[info['account']] = until = \
|
292
303
|
time.time() + self.account_suppression_time
|
@@ -325,12 +336,12 @@ class ContainerUpdater(Daemon):
|
|
325
336
|
'X-Backend-Storage-Policy-Index': storage_policy_index,
|
326
337
|
'user-agent': self.user_agent}
|
327
338
|
conn = http_connect(
|
328
|
-
node['
|
329
|
-
'PUT', container, headers=headers)
|
339
|
+
node['replication_ip'], node['replication_port'],
|
340
|
+
node['device'], part, 'PUT', container, headers=headers)
|
330
341
|
except (Exception, Timeout):
|
331
|
-
self.logger.exception(
|
332
|
-
'ERROR account update failed with '
|
333
|
-
|
342
|
+
self.logger.exception(
|
343
|
+
'ERROR account update failed with %s (will retry later):',
|
344
|
+
node_to_string(node, replication=True))
|
334
345
|
return HTTP_INTERNAL_SERVER_ERROR
|
335
346
|
with Timeout(self.node_timeout):
|
336
347
|
try:
|
@@ -340,7 +351,17 @@ class ContainerUpdater(Daemon):
|
|
340
351
|
except (Exception, Timeout):
|
341
352
|
if self.logger.getEffectiveLevel() <= logging.DEBUG:
|
342
353
|
self.logger.exception(
|
343
|
-
|
354
|
+
'Exception with %s',
|
355
|
+
node_to_string(node, replication=True))
|
344
356
|
return HTTP_INTERNAL_SERVER_ERROR
|
345
357
|
finally:
|
346
358
|
conn.close()
|
359
|
+
|
360
|
+
|
361
|
+
def main():
|
362
|
+
conf_file, options = parse_options(once=True)
|
363
|
+
run_daemon(ContainerUpdater, conf_file, **options)
|
364
|
+
|
365
|
+
|
366
|
+
if __name__ == '__main__':
|
367
|
+
main()
|