launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #21232
[Merge] lp:~wgrant/launchpad/bug-1642411 into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/bug-1642411 into lp:launchpad.
Commit message:
Fix delete_unwanted_swift_files to not crash on segments.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1642411 in Launchpad itself: "librarian-gc crashes on segmented Swift files"
https://bugs.launchpad.net/launchpad/+bug/1642411
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/bug-1642411/+merge/311092
Fix delete_unwanted_swift_files to not crash on segments.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/bug-1642411 into lp:launchpad.
=== modified file 'lib/lp/services/librarianserver/librariangc.py'
--- lib/lp/services/librarianserver/librariangc.py 2016-06-20 07:18:17 +0000
+++ lib/lp/services/librarianserver/librariangc.py 2016-11-16 23:20:45 +0000
@@ -725,7 +725,7 @@
names = sorted(
swift_connection.get_container(
container, full_listing=True)[1],
- key=lambda x: int(x['name']))
+ key=lambda x: map(int, x['name'].split('/')))
for name in names:
yield (container, name)
except swiftclient.ClientException as x:
=== modified file 'lib/lp/services/librarianserver/tests/test_gc.py'
--- lib/lp/services/librarianserver/tests/test_gc.py 2016-06-20 07:18:17 +0000
+++ lib/lp/services/librarianserver/tests/test_gc.py 2016-11-16 23:20:45 +0000
@@ -21,6 +21,7 @@
from contextlib import contextmanager
from sqlobject import SQLObjectNotFound
+from storm.store import Store
from swiftclient import client as swiftclient
import transaction
@@ -43,7 +44,10 @@
from lp.services.log.logger import BufferLogger
from lp.services.features.testing import FeatureFixture
from lp.services.utils import utc_now
-from lp.testing import TestCase
+from lp.testing import (
+ monkey_patch,
+ TestCase,
+ )
from lp.testing.dbuser import switch_dbuser
from lp.testing.layers import (
LaunchpadZopelessLayer,
@@ -723,8 +727,10 @@
swift.to_swift(BufferLogger(), remove_func=os.unlink)
assert not os.path.exists(path), "to_swift failed to move files"
- def file_exists(self, content_id):
+ def file_exists(self, content_id, suffix=None):
container, name = swift.swift_location(content_id)
+ if suffix:
+ name += suffix
with swift.connection() as swift_connection:
try:
swift_connection.head_object(container, name)
@@ -739,6 +745,58 @@
with swift.connection() as swift_connection:
swift_connection.delete_object(container, name)
+ def test_delete_unwanted_files_handles_segments(self):
+ # Large files are handled by Swift as multiple segments joined
+ # by a manifest. GC treats the segments like the original file.
+ switch_dbuser('testadmin')
+ content = 'uploading to swift bigly'
+ big1_lfa = LibraryFileAlias.get(self.client.addFile(
+ 'foo.txt', len(content), StringIO(content), 'text/plain'))
+ big1_id = big1_lfa.contentID
+
+ big2_lfa = LibraryFileAlias.get(self.client.addFile(
+ 'bar.txt', len(content), StringIO(content), 'text/plain'))
+ big2_id = big2_lfa.contentID
+ transaction.commit()
+
+ for lfc_id in (big1_id, big2_id):
+ # Make the files old so they don't look in-progress.
+ os.utime(swift.filesystem_path(lfc_id), (0, 0))
+
+ switch_dbuser(config.librarian_gc.dbuser)
+
+ # Force the files to be segmented as if they were large.
+ with monkey_patch(swift, MAX_SWIFT_OBJECT_SIZE=4):
+ swift.to_swift(BufferLogger(), remove_func=os.unlink)
+
+ def segment_existence(lfc_id):
+ return [
+ self.file_exists(lfc_id, suffix=suffix)
+ for suffix in (None, '/0000', '/0001')]
+
+ # Both files and their segments exist in Swift.
+ self.assertEqual([True, True, True], segment_existence(big1_id))
+ self.assertEqual([True, True, True], segment_existence(big2_id))
+
+ # All the segments survive the first purge.
+ with self.librariangc_thinking_it_is_tomorrow():
+ librariangc.delete_unwanted_files(self.con)
+ self.assertEqual([True, True, True], segment_existence(big1_id))
+ self.assertEqual([True, True, True], segment_existence(big2_id))
+
+ # Remove the first file from the DB.
+ content = big1_lfa.content
+ Store.of(big1_lfa).remove(big1_lfa)
+ Store.of(content).remove(content)
+ transaction.commit()
+
+ # The first file and its segments are removed, but the second is
+ # intact.
+ with self.librariangc_thinking_it_is_tomorrow():
+ librariangc.delete_unwanted_files(self.con)
+ self.assertEqual([False, False, False], segment_existence(big1_id))
+ self.assertEqual([True, True, True], segment_existence(big2_id))
+
class TestBlobCollection(TestCase):
layer = LaunchpadZopelessLayer
Follow ups