From 2a934756dd05992b409bfcd229bc7a6c06bff929 Mon Sep 17 00:00:00 2001 From: bescoto Date: Wed, 14 Dec 2005 03:13:57 +0000 Subject: Fix for KeyError while incrementing in v1.1.3 git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/trunk@706 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109 --- rdiff-backup/CHANGELOG | 4 +++- rdiff-backup/rdiff_backup/backup.py | 43 ++++++++++++++++++++++++++++++++++--- rdiff-backup/testing/finaltest.py | 14 ++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG index a425b50..faa7c09 100644 --- a/rdiff-backup/CHANGELOG +++ b/rdiff-backup/CHANGELOG @@ -1,4 +1,4 @@ -New in v1.1.4 (????/??/??) +New in v1.1.4 (2005/12/13) -------------------------- Quoting should be enabled only as needed between case-sensitive and @@ -7,6 +7,8 @@ non-case-sensitive systems (thanks for Andrew Ferguson for report). Files with ACLs will not be unnecessarily marked as changed (bug report by Carsten Lorenz). +Fix for common KeyError bug introduced in v1.1.3. + New in v1.1.3 (2005/11/25) -------------------------- diff --git a/rdiff-backup/rdiff_backup/backup.py b/rdiff-backup/rdiff_backup/backup.py index 3041bd9..819ae91 100644 --- a/rdiff-backup/rdiff_backup/backup.py +++ b/rdiff-backup/rdiff_backup/backup.py @@ -300,6 +300,10 @@ class CacheCollatedPostProcess: # computed once. self.inode_digest_dict = {} + # Contains list of (index, (source_rorp, diff_rorp)) pairs for + # the parent directories of the last item in the cache. + self.parent_list = [] + def __iter__(self): return self def next(self): @@ -354,6 +358,30 @@ class CacheCollatedPostProcess: self.post_process(old_source_rorp, old_dest_rorp, changed_flag, success_flag, inc) if self.dir_perms_list: self.reset_dir_perms(first_index) + self.update_parent_list(first_index, old_source_rorp, old_dest_rorp) + + def update_parent_list(self, index, src_rorp, dest_rorp): + """Update the parent cache with the recently expired main cache entry + + This method keeps parent directories in the secondary parent + cache until all their children have expired from the main + cache. This is necessary because we may realize we need a + parent directory's information after we have processed many + subfiles. + + """ + if not (src_rorp and src_rorp.isdir() or + dest_rorp and dest_rorp.isdir()): return # neither is directory + if not self.parent_list: assert index == (), index + else: + last_parent_index = self.parent_list[-1][0] + lp_index, li = len(last_parent_index), len(index) + if li > lp_index: # descended into previous parent + assert li == lp_index + 1, (index, last_parent_index) + else: # In new directory + assert last_parent_index[:li-1] == index[:-1], index + self.parent_list = self.parent_list[:li] + self.parent_list.append((index, (src_rorp, dest_rorp))) def post_process(self, source_rorp, dest_rorp, changed, success, inc): """Post process source_rorp and dest_rorp. @@ -411,20 +439,29 @@ class CacheCollatedPostProcess: """Set the increment of the current file""" self.cache_dict[index][4] = inc + def get_parent_rorps(self, index): + """Retrieve (src_rorp, dest_rorp) pair from parent cache""" + for parent_index, pair in self.parent_list: + if parent_index == index: return pair + raise KeyError(index) + def get_rorps(self, index): """Retrieve (source_rorp, dest_rorp) from cache""" - return self.cache_dict[index][:2] + try: return self.cache_dict[index][:2] + except KeyError: return self.get_parent_rorps(index) def get_source_rorp(self, index): """Retrieve source_rorp with given index from cache""" assert index >= self.cache_indicies[0], \ ("CCPP index out of order: %s %s" % (repr(index), repr(self.cache_indicies[0]))) - return self.cache_dict[index][0] + try: return self.cache_dict[index][0] + except KeyError: return self.get_parent_rorps(index)[0] def get_mirror_rorp(self, index): """Retrieve mirror_rorp with given index from cache""" - return self.cache_dict[index][1] + try: return self.cache_dict[index][1] + except KeyError: return self.get_parent_rorps(index)[1] def update_hash(self, index, sha1sum): """Update the source rorp's SHA1 hash""" diff --git a/rdiff-backup/testing/finaltest.py b/rdiff-backup/testing/finaltest.py index 6dc73f2..d773c21 100644 --- a/rdiff-backup/testing/finaltest.py +++ b/rdiff-backup/testing/finaltest.py @@ -711,5 +711,19 @@ class FinalBugs(PathSetter): rp1_d_f.setdata() assert rp1_d_f.isreg(), 'File %s corrupted' % (rp1_d_f.path,) + def test_CCPP_keyerror(self): + """Test when no change until middle of a directory + + This tests CCPP, to make sure it isn't asked to provide rorps + for indicies that are out of the cache. + + """ + self.delete_tmpdirs() + rdiff_backup(1, 1, 'testfiles/bigdir', 'testfiles/output') + rp = rpath.RPath(Globals.local_connection, + 'testfiles/bigdir/subdir3/subdir49/file49') + assert rp.isreg(), rp + rp.touch() + rdiff_backup(1, 1, 'testfiles/bigdir', 'testfiles/output') if __name__ == "__main__": unittest.main() -- cgit v1.2.1