Merge lp:~wgrant/launchpad/bug-1642411 into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 18274
Proposed branch: lp:~wgrant/launchpad/bug-1642411
Merge into: lp:launchpad
Diff against target: 107 lines (+61/-3)
2 files modified
lib/lp/services/librarianserver/librariangc.py (+1/-1)
lib/lp/services/librarianserver/tests/test_gc.py (+60/-2)
To merge this branch: bzr merge lp:~wgrant/launchpad/bug-1642411
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+311092@code.launchpad.net

Commit message

Fix delete_unwanted_swift_files to not crash on segments.

Description of the change

Fix delete_unwanted_swift_files to not crash on segments.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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 @@
725 names = sorted(725 names = sorted(
726 swift_connection.get_container(726 swift_connection.get_container(
727 container, full_listing=True)[1],727 container, full_listing=True)[1],
728 key=lambda x: int(x['name']))728 key=lambda x: map(int, x['name'].split('/')))
729 for name in names:729 for name in names:
730 yield (container, name)730 yield (container, name)
731 except swiftclient.ClientException as x:731 except swiftclient.ClientException as x:
732732
=== 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 @@
2121
22from contextlib import contextmanager22from contextlib import contextmanager
23from sqlobject import SQLObjectNotFound23from sqlobject import SQLObjectNotFound
24from storm.store import Store
24from swiftclient import client as swiftclient25from swiftclient import client as swiftclient
25import transaction26import transaction
2627
@@ -43,7 +44,10 @@
43from lp.services.log.logger import BufferLogger44from lp.services.log.logger import BufferLogger
44from lp.services.features.testing import FeatureFixture45from lp.services.features.testing import FeatureFixture
45from lp.services.utils import utc_now46from lp.services.utils import utc_now
46from lp.testing import TestCase47from lp.testing import (
48 monkey_patch,
49 TestCase,
50 )
47from lp.testing.dbuser import switch_dbuser51from lp.testing.dbuser import switch_dbuser
48from lp.testing.layers import (52from lp.testing.layers import (
49 LaunchpadZopelessLayer,53 LaunchpadZopelessLayer,
@@ -723,8 +727,10 @@
723 swift.to_swift(BufferLogger(), remove_func=os.unlink)727 swift.to_swift(BufferLogger(), remove_func=os.unlink)
724 assert not os.path.exists(path), "to_swift failed to move files"728 assert not os.path.exists(path), "to_swift failed to move files"
725729
726 def file_exists(self, content_id):730 def file_exists(self, content_id, suffix=None):
727 container, name = swift.swift_location(content_id)731 container, name = swift.swift_location(content_id)
732 if suffix:
733 name += suffix
728 with swift.connection() as swift_connection:734 with swift.connection() as swift_connection:
729 try:735 try:
730 swift_connection.head_object(container, name)736 swift_connection.head_object(container, name)
@@ -739,6 +745,58 @@
739 with swift.connection() as swift_connection:745 with swift.connection() as swift_connection:
740 swift_connection.delete_object(container, name)746 swift_connection.delete_object(container, name)
741747
748 def test_delete_unwanted_files_handles_segments(self):
749 # Large files are handled by Swift as multiple segments joined
750 # by a manifest. GC treats the segments like the original file.
751 switch_dbuser('testadmin')
752 content = 'uploading to swift bigly'
753 big1_lfa = LibraryFileAlias.get(self.client.addFile(
754 'foo.txt', len(content), StringIO(content), 'text/plain'))
755 big1_id = big1_lfa.contentID
756
757 big2_lfa = LibraryFileAlias.get(self.client.addFile(
758 'bar.txt', len(content), StringIO(content), 'text/plain'))
759 big2_id = big2_lfa.contentID
760 transaction.commit()
761
762 for lfc_id in (big1_id, big2_id):
763 # Make the files old so they don't look in-progress.
764 os.utime(swift.filesystem_path(lfc_id), (0, 0))
765
766 switch_dbuser(config.librarian_gc.dbuser)
767
768 # Force the files to be segmented as if they were large.
769 with monkey_patch(swift, MAX_SWIFT_OBJECT_SIZE=4):
770 swift.to_swift(BufferLogger(), remove_func=os.unlink)
771
772 def segment_existence(lfc_id):
773 return [
774 self.file_exists(lfc_id, suffix=suffix)
775 for suffix in (None, '/0000', '/0001')]
776
777 # Both files and their segments exist in Swift.
778 self.assertEqual([True, True, True], segment_existence(big1_id))
779 self.assertEqual([True, True, True], segment_existence(big2_id))
780
781 # All the segments survive the first purge.
782 with self.librariangc_thinking_it_is_tomorrow():
783 librariangc.delete_unwanted_files(self.con)
784 self.assertEqual([True, True, True], segment_existence(big1_id))
785 self.assertEqual([True, True, True], segment_existence(big2_id))
786
787 # Remove the first file from the DB.
788 content = big1_lfa.content
789 Store.of(big1_lfa).remove(big1_lfa)
790 Store.of(content).remove(content)
791 transaction.commit()
792
793 # The first file and its segments are removed, but the second is
794 # intact.
795 with self.librariangc_thinking_it_is_tomorrow():
796 librariangc.delete_unwanted_files(self.con)
797 self.assertEqual([False, False, False], segment_existence(big1_id))
798 self.assertEqual([True, True, True], segment_existence(big2_id))
799
742800
743class TestBlobCollection(TestCase):801class TestBlobCollection(TestCase):
744 layer = LaunchpadZopelessLayer802 layer = LaunchpadZopelessLayer