Merge lp:~verterok/ubuntuone-client/fix-776386-1-6 into lp:ubuntuone-client/stable-1-6

Proposed by Guillermo Gonzalez
Status: Merged
Approved by: dobey
Approved revision: 968
Merged at revision: 970
Proposed branch: lp:~verterok/ubuntuone-client/fix-776386-1-6
Merge into: lp:ubuntuone-client/stable-1-6
Diff against target: 151 lines (+76/-9)
2 files modified
tests/syncdaemon/test_tritcask.py (+48/-0)
ubuntuone/syncdaemon/tritcask.py (+28/-9)
To merge this branch: bzr merge lp:~verterok/ubuntuone-client/fix-776386-1-6
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Approve
Facundo Batista (community) Approve
Review via email: mp+75623@code.launchpad.net

Commit message

Fix Tritcask._find_data_files method to handle the case of broken/corrupted data files (when opening the file).

Description of the change

This branch fix Tritcask._find_data_files method to handle the case of broken/corrupted data files (when opening the file).
It basically rename any broken "immutable" data file doing: s/".inactive"/".broken"/

To post a comment you must log in.
Revision history for this message
Facundo Batista (facundo) :
review: Approve
Revision history for this message
Guillermo Gonzalez (verterok) wrote :

Approving with one review

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'tests/syncdaemon/test_tritcask.py'
--- tests/syncdaemon/test_tritcask.py 2011-04-05 16:50:31 +0000
+++ tests/syncdaemon/test_tritcask.py 2011-09-15 19:58:34 +0000
@@ -37,9 +37,11 @@
37 HINT,37 HINT,
38 INACTIVE,38 INACTIVE,
39 DEAD,39 DEAD,
40 BROKEN,
40 BadCrc,41 BadCrc,
41 BadHeader,42 BadHeader,
42 DataFile,43 DataFile,
44 ImmutableDataFile,
43 TempDataFile,45 TempDataFile,
44 DeadDataFile,46 DeadDataFile,
45 HintFile,47 HintFile,
@@ -841,6 +843,52 @@
841 self.assertEqual(files, filenames)843 self.assertEqual(files, filenames)
842 db.shutdown()844 db.shutdown()
843845
846 def test_find_data_files_immutable_open_error(self):
847 """Test the _find_data_files method failing to open a file."""
848 data_file = DataFile(self.base_dir)
849 data_file.write(0, 'foo_0', 'bar_0')
850 immutable_file = data_file.make_immutable()
851 immutable_file.close()
852 # patch the open call and make it fail
853 def fail_open(filename, *a):
854 """Always fail."""
855 raise IOError("I'm a broken file.")
856 self.patch(ImmutableDataFile, '_open', fail_open)
857 db = Tritcask(self.base_dir)
858 self.addCleanup(db.shutdown)
859 files = [fn.filename for fn in sorted(db._immutable.values(),
860 key=attrgetter('filename'))]
861 self.assertNotIn(immutable_file.filename, files)
862 # check the logs
863 msg = ("Failed to open %s, renaming it to: %s - error: %s" % \
864 (immutable_file.filename,
865 immutable_file.filename.replace(INACTIVE, BROKEN),
866 IOError("I'm a broken file")))
867 self.assertTrue(self.memento.check_warning(msg))
868
869 def test_find_data_files_live_open_error(self):
870 """Test the _find_data_files method failing to open a file."""
871 data_file = DataFile(self.base_dir)
872 data_file.write(0, 'foo_0', 'bar_0')
873 data_file.close()
874 # patch the open call and make it fail
875 orig_open = DataFile._open
876 def fail_open(filename, *a):
877 """Always fail only once."""
878 self.patch(DataFile, '_open', orig_open)
879 raise IOError("I'm a broken file.")
880 self.patch(DataFile, '_open', fail_open)
881 db = Tritcask(self.base_dir)
882 self.addCleanup(db.shutdown)
883 self.assertNotEqual(data_file.filename, db.live_file.filename)
884 # check the logs
885 self.memento.debug = True
886 msg = ("Failed to open %s, renaming it to: %s - error: %s" % \
887 (data_file.filename,
888 data_file.filename.replace(LIVE, BROKEN),
889 IOError("I'm a broken file")))
890 self.assertTrue(self.memento.check_warning(msg))
891
844 def test_build_keydir_on_init(self):892 def test_build_keydir_on_init(self):
845 """Test _build_keydir method."""893 """Test _build_keydir method."""
846 db = Tritcask(self.base_dir)894 db = Tritcask(self.base_dir)
847895
=== modified file 'ubuntuone/syncdaemon/tritcask.py'
--- ubuntuone/syncdaemon/tritcask.py 2011-04-05 16:50:31 +0000
+++ ubuntuone/syncdaemon/tritcask.py 2011-09-15 19:58:34 +0000
@@ -55,6 +55,7 @@
55INACTIVE = '.inactive'55INACTIVE = '.inactive'
56HINT = '.hint'56HINT = '.hint'
57DEAD = '.dead'57DEAD = '.dead'
58BROKEN = '.broken'
5859
59VERSION = 'v1'60VERSION = 'v1'
60FILE_SUFFIX = '.tritcask-%s.data' % VERSION61FILE_SUFFIX = '.tritcask-%s.data' % VERSION
@@ -73,6 +74,7 @@
73class BadHeader(Exception):74class BadHeader(Exception):
74 """A Exception for Bad header value."""75 """A Exception for Bad header value."""
7576
77
76TritcaskEntry = namedtuple('TritcaskEntry', ['crc32', 'tstamp', 'key_sz',78TritcaskEntry = namedtuple('TritcaskEntry', ['crc32', 'tstamp', 'key_sz',
77 'value_sz', 'row_type', 'key', 'value', 'value_pos'])79 'value_sz', 'row_type', 'key', 'value', 'value_pos'])
7880
@@ -148,12 +150,12 @@
148 """150 """
149 self.has_bad_crc = False151 self.has_bad_crc = False
150 self.has_bad_data = False152 self.has_bad_data = False
153 self.fd = None
151 if filename is None:154 if filename is None:
152 filename = self._get_next_file_id() + LIVE + FILE_SUFFIX155 filename = self._get_next_file_id() + LIVE + FILE_SUFFIX
153 self.filename = os.path.join(base_path, filename)156 self.filename = os.path.join(base_path, filename)
154 self.file_id = _get_file_id(filename)157 self.file_id = _get_file_id(filename)
155 self.hint_filename = os.path.join(base_path, filename + HINT)158 self.hint_filename = os.path.join(base_path, filename + HINT)
156 self.fd = None
157 self._open()159 self._open()
158160
159 @property161 @property
@@ -645,23 +647,40 @@
645 """Collect the files we need to work with."""647 """Collect the files we need to work with."""
646 logger.debug("lookingup data files")648 logger.debug("lookingup data files")
647 dead_files = 0649 dead_files = 0
650 broken_files = 0
648 files = os.listdir(self.base_path)651 files = os.listdir(self.base_path)
649 for filename in files:652 for filename in files:
653 # first check for hint and dead
650 if is_hint(filename):654 if is_hint(filename):
651 continue655 continue
652 if is_live(filename):
653 self.live_file = DataFile(self.base_path, filename)
654 elif is_immutable(filename):
655 # it's an immutable file
656 data_file = ImmutableDataFile(self.base_path, filename)
657 self._immutable[data_file.file_id] = data_file
658 elif is_dead(filename):656 elif is_dead(filename):
659 # a dead file...let's remove it657 # a dead file...let's remove it
660 dead_files += 1658 dead_files += 1
661 DeadDataFile(self.base_path, filename).delete()659 DeadDataFile(self.base_path, filename).delete()
660 continue
661 # if it's a live or immutable file try to open it, but if it's
662 # "broken", just rename it and continue
663 try:
664 if is_live(filename):
665 self.live_file = DataFile(self.base_path, filename)
666 elif is_immutable(filename):
667 # it's an immutable file
668 data_file = ImmutableDataFile(self.base_path, filename)
669 self._immutable[data_file.file_id] = data_file
670 except IOError, e:
671 # oops, failed to open the file..discard it
672 broken_files += 1
673 orig = os.path.join(self.base_path, filename)
674 # get the kind of the file so we can rename it
675 kind = LIVE if is_live(filename) else INACTIVE
676 dest = orig.replace(kind, BROKEN)
677 logger.warning("Failed to open %s, renaming it to: %s - "
678 "error: %s", orig, dest, e)
679 # rename it to "broken"
680 os.rename(orig, dest)
662 # immutable files + live681 # immutable files + live
663 logger.info("found %s data files and %s dead files",682 logger.info("found %s data files, %s dead and %s broken files",
664 len(self._immutable)+1, dead_files)683 len(self._immutable)+1, dead_files, broken_files)
665684
666 def rotate(self, create_file=True):685 def rotate(self, create_file=True):
667 """Rotate the live file only if it already exsits."""686 """Rotate the live file only if it already exsits."""

Subscribers

People subscribed via source and target branches