Remove all DLO segments on upload of replacement

Previously, only the first container-listing's worth of segments was
deleted, which would leave behind orphaned segments when the object was
very large with small segments or the server's container_listing_limit
was small.

In addition, process DLO and SLO deletions on the segment thread pool,
rather than the object thread pool.

Change-Id: I1587375261a6237fa55a9cb96bda8dae918cc795
Related-Bug: #1418007
This commit is contained in:
Tim Burke 2015-03-05 11:58:26 -08:00
parent dcf2124d41
commit d931ec1381
2 changed files with 29 additions and 19 deletions
swiftclient
tests/unit

@ -1728,19 +1728,19 @@ class SwiftService(object):
if old_manifest or old_slo_manifest_paths: if old_manifest or old_slo_manifest_paths:
drs = [] drs = []
delobjsmap = {}
if old_manifest: if old_manifest:
scontainer, sprefix = old_manifest.split('/', 1) scontainer, sprefix = old_manifest.split('/', 1)
scontainer = unquote(scontainer) scontainer = unquote(scontainer)
sprefix = unquote(sprefix).rstrip('/') + '/' sprefix = unquote(sprefix).rstrip('/') + '/'
delobjs = [] delobjsmap[scontainer] = []
for delobj in conn.get_container(scontainer, for part in self.list(scontainer, {'prefix': sprefix}):
prefix=sprefix)[1]: if not part["success"]:
delobjs.append(delobj['name']) raise part["error"]
for dr in self.delete(container=scontainer, delobjsmap[scontainer].extend(
objects=delobjs): seg['name'] for seg in part['listing'])
drs.append(dr)
if old_slo_manifest_paths: if old_slo_manifest_paths:
delobjsmap = {}
for seg_to_delete in old_slo_manifest_paths: for seg_to_delete in old_slo_manifest_paths:
if seg_to_delete in new_slo_manifest_paths: if seg_to_delete in new_slo_manifest_paths:
continue continue
@ -1749,10 +1749,18 @@ class SwiftService(object):
delobjs_cont = delobjsmap.get(scont, []) delobjs_cont = delobjsmap.get(scont, [])
delobjs_cont.append(sobj) delobjs_cont.append(sobj)
delobjsmap[scont] = delobjs_cont delobjsmap[scont] = delobjs_cont
for (dscont, dsobjs) in delobjsmap.items():
for dr in self.delete(container=dscont, del_segs = []
objects=dsobjs): for dscont, dsobjs in delobjsmap.items():
drs.append(dr) for dsobj in dsobjs:
del_seg = self.thread_manager.segment_pool.submit(
self._delete_segment, dscont, dsobj,
results_queue=results_queue
)
del_segs.append(del_seg)
for del_seg in interruptable_as_completed(del_segs):
drs.append(del_seg.result())
res['segment_delete_results'] = drs res['segment_delete_results'] = drs
# return dict for printing # return dict for printing

@ -489,11 +489,11 @@ class TestShell(unittest.TestCase):
expected_delete_calls = [ expected_delete_calls = [
mock.call( mock.call(
b'container1', b'old_seg1', b'container1', b'old_seg1',
query_string=None, response_dict={} response_dict={}
), ),
mock.call( mock.call(
b'container2', b'old_seg2', b'container2', b'old_seg2',
query_string=None, response_dict={} response_dict={}
) )
] ]
self.assertEqual( self.assertEqual(
@ -538,9 +538,11 @@ class TestShell(unittest.TestCase):
] ]
connection.return_value.get_container.side_effect = [ connection.return_value.get_container.side_effect = [
[None, [{'name': 'prefix_a', 'bytes': 0, [None, [{'name': 'prefix_a', 'bytes': 0,
'last_modified': '123T456'}, 'last_modified': '123T456'}]],
{'name': 'prefix_b', 'bytes': 0, # Have multiple pages worth of DLO segments
'last_modified': '123T456'}]] [None, [{'name': 'prefix_b', 'bytes': 0,
'last_modified': '123T456'}]],
[None, []]
] ]
connection.return_value.put_object.return_value = ( connection.return_value.put_object.return_value = (
'd41d8cd98f00b204e9800998ecf8427e') 'd41d8cd98f00b204e9800998ecf8427e')
@ -555,11 +557,11 @@ class TestShell(unittest.TestCase):
expected_delete_calls = [ expected_delete_calls = [
mock.call( mock.call(
'container1', 'prefix_a', 'container1', 'prefix_a',
query_string=None, response_dict={} response_dict={}
), ),
mock.call( mock.call(
'container1', 'prefix_b', 'container1', 'prefix_b',
query_string=None, response_dict={} response_dict={}
) )
] ]
self.assertEqual( self.assertEqual(