Rev 4753: (spiv) Fix bug in CHKMap.apply_delta that was generating non-canonical CHK in file:///home/pqm/archives/thelove/bzr/2.0/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Wed Jul 14 10:39:37 BST 2010


At file:///home/pqm/archives/thelove/bzr/2.0/

------------------------------------------------------------
revno: 4753 [merge]
revision-id: pqm at pqm.ubuntu.com-20100714093935-jtbipw6qj2uvzhzk
parent: pqm at pqm.ubuntu.com-20100713120413-c0euzhlqz4aenrye
parent: andrew.bennetts at canonical.com-20100714080610-6obmjlgn3nwsbtaw
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: 2.0
timestamp: Wed 2010-07-14 10:39:35 +0100
message:
  (spiv) Fix bug in CHKMap.apply_delta that was generating non-canonical CHK
   maps when entries are removed. (Andrew Bennetts)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/chk_map.py              chk_map.py-20081001014447-ue6kkuhofvdecvxa-1
  bzrlib/tests/test_chk_map.py   test_chk_map.py-20081001014447-ue6kkuhofvdecvxa-2
=== modified file 'NEWS'
--- a/NEWS	2010-07-13 10:21:19 +0000
+++ b/NEWS	2010-07-14 07:46:55 +0000
@@ -29,6 +29,11 @@
 * Don't traceback trying to unversion children files of an already
   unversioned directory.  (Vincent Ladeuil, #494221)
 
+* Prevent ``CHKMap.apply_delta`` from generating non-canonical CHK maps,
+  which can result in "missing referenced chk root keys" errors when
+  fetching from repositories with affected revisions.
+  (Andrew Bennetts, #522637)
+
 * Raise ValueError instead of a string exception.
   (John Arbash Meinel, #586926)
 

=== modified file 'bzrlib/chk_map.py'
--- a/bzrlib/chk_map.py	2009-08-04 14:10:09 +0000
+++ b/bzrlib/chk_map.py	2010-07-14 07:46:55 +0000
@@ -67,8 +67,6 @@
 _INTERESTING_NEW_SIZE = 50
 # If a ChildNode shrinks by more than this amount, we check for a remap
 _INTERESTING_SHRINKAGE_LIMIT = 20
-# If we delete more than this many nodes applying a delta, we check for a remap
-_INTERESTING_DELETES_LIMIT = 5
 
 
 def _search_key_plain(key):
@@ -110,7 +108,7 @@
             into the map; if old_key is not None, then the old mapping
             of old_key is removed.
         """
-        delete_count = 0
+        has_deletes = False
         # Check preconditions first.
         new_items = set([key for (old, key, value) in delta if key is not None
             and old is None])
@@ -122,12 +120,11 @@
         for old, new, value in delta:
             if old is not None and old != new:
                 self.unmap(old, check_remap=False)
-                delete_count += 1
+                has_deletes = True
         for old, new, value in delta:
             if new is not None:
                 self.map(new, value)
-        if delete_count > _INTERESTING_DELETES_LIMIT:
-            trace.mutter("checking remap as %d deletions", delete_count)
+        if has_deletes:
             self._check_remap()
         return self._save()
 
@@ -535,7 +532,7 @@
         """Check if nodes can be collapsed."""
         self._ensure_root()
         if type(self._root_node) is InternalNode:
-            self._root_node._check_remap(self._store)
+            self._root_node = self._root_node._check_remap(self._store)
 
     def _save(self):
         """Save the map completely.

=== modified file 'bzrlib/tests/test_chk_map.py'
--- a/bzrlib/tests/test_chk_map.py	2009-07-16 23:28:49 +0000
+++ b/bzrlib/tests/test_chk_map.py	2010-07-14 08:06:10 +0000
@@ -466,6 +466,25 @@
         # updated key.
         self.assertEqual(new_root, chkmap._root_node._key)
 
+    def test_apply_delete_to_internal_node(self):
+        # applying a delta should be convert an internal root node to a leaf
+        # node if the delta shrinks the map enough.
+        store = self.get_chk_bytes()
+        chkmap = CHKMap(store, None)
+        # Add three items: 2 small enough to fit in one node, and one huge to
+        # force multiple nodes.
+        chkmap._root_node.set_maximum_size(100)
+        chkmap.map(('small',), 'value')
+        chkmap.map(('little',), 'value')
+        chkmap.map(('very-big',), 'x' * 100)
+        # (Check that we have constructed the scenario we want to test)
+        self.assertIsInstance(chkmap._root_node, InternalNode)
+        # Delete the huge item so that the map fits in one node again.
+        delta = [(('very-big',), None, None)]
+        chkmap.apply_delta(delta)
+        self.assertCanonicalForm(chkmap)
+        self.assertIsInstance(chkmap._root_node, LeafNode)
+
     def test_apply_new_keys_must_be_new(self):
         # applying a delta (None, "a", "b") to a map with 'a' in it generates
         # an error.




More information about the bazaar-commits mailing list