Rev 5880: (jameinel) Fix bug #781168, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue May 17 17:32:18 UTC 2011


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5880 [merge]
revision-id: pqm at pqm.ubuntu.com-20110517173151-cyrafeu82ccamiwv
parent: pqm at pqm.ubuntu.com-20110517153909-yk7lj81o32awzidy
parent: john at arbash-meinel.com-20110517132954-gyoh36gikwi6moxh
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2011-05-17 17:31:51 +0000
message:
  (jameinel) Fix bug #781168,
   and allow WT.update_basis_by_delta to not require the delta makes the basis
   match the current state. (John A Meinel)
modified:
  bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
  bzrlib/tests/test_inv.py       testinv.py-20050722220913-1dc326138d1a5892
  doc/en/release-notes/bzr-2.4.txt bzr2.4.txt-20110114053217-k7ym9jfz243fddjm-1
=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py	2011-05-11 01:58:47 +0000
+++ b/bzrlib/dirstate.py	2011-05-17 13:17:39 +0000
@@ -1326,6 +1326,14 @@
             raise
         return result
 
+    def _check_delta_is_valid(self, delta):
+        return list(inventory._check_delta_unique_ids(
+                    inventory._check_delta_unique_old_paths(
+                    inventory._check_delta_unique_new_paths(
+                    inventory._check_delta_ids_match_entry(
+                    inventory._check_delta_ids_are_valid(
+                    inventory._check_delta_new_path_entry_both_or_None(delta)))))))
+
     def update_by_delta(self, delta):
         """Apply an inventory delta to the dirstate for tree 0
 
@@ -1349,13 +1357,8 @@
         new_ids = set()
         # This loop transforms the delta to single atomic operations that can
         # be executed and validated.
-        for old_path, new_path, file_id, inv_entry in sorted(
-            inventory._check_delta_unique_old_paths(
-            inventory._check_delta_unique_new_paths(
-            inventory._check_delta_ids_match_entry(
-            inventory._check_delta_ids_are_valid(
-            inventory._check_delta_new_path_entry_both_or_None(delta))))),
-            reverse=True):
+        delta = sorted(self._check_delta_is_valid(delta), reverse=True)
+        for old_path, new_path, file_id, inv_entry in delta:
             if (file_id in insertions) or (file_id in removals):
                 raise errors.InconsistentDelta(old_path or new_path, file_id,
                     "repeated file_id")
@@ -1475,9 +1478,6 @@
         Note that an exception during the operation of this method will leave
         the dirstate in a corrupt state where it should not be saved.
 
-        Finally, we expect all changes to be synchronising the basis tree with
-        the working tree.
-
         :param new_revid: The new revision id for the trees parent.
         :param delta: An inventory delta (see apply_inventory_delta) describing
             the changes from the current left most parent revision to new_revid.
@@ -1495,7 +1495,7 @@
 
         self._parents[0] = new_revid
 
-        delta = sorted(delta, reverse=True)
+        delta = sorted(self._check_delta_is_valid(delta), reverse=True)
         adds = []
         changes = []
         deletes = []
@@ -1653,7 +1653,17 @@
         for old_path, new_path, file_id, new_details, real_add in adds:
             # the entry for this file_id must be in tree 0.
             entry = self._get_entry(0, file_id, new_path)
-            if entry[0] is None or entry[0][2] != file_id:
+            if entry[0] is None:
+                # new_path is not versioned in the active WT state,
+                # but we are adding it to the basis tree state, we
+                # need to create a new entry record for it.
+                dirname, basename = osutils.split(new_path)
+                entry_key = (dirname, basename, file_id)
+                _, block = self._find_block(entry_key, add_if_missing=True)
+                index, _ = self._find_entry_index(entry_key, block)
+                entry = (entry_key, [DirState.NULL_PARENT_DETAILS]*2)
+                block.insert(index, entry)
+            elif entry[0][2] != file_id:
                 self._changes_aborted = True
                 raise errors.InconsistentDelta(new_path, file_id,
                     'working tree does not contain new entry')
@@ -1719,12 +1729,27 @@
                 raise errors.InconsistentDelta(old_path, file_id,
                     'mismatched file_id in tree 1')
             if real_delete:
-                if entry[1][0][0] != 'a':
-                    self._changes_aborted = True
-                    raise errors.InconsistentDelta(old_path, file_id,
-                            'This was marked as a real delete, but the WT state'
-                            ' claims that it still exists and is versioned.')
-                del self._dirblocks[block_index][1][entry_index]
+                if entry[1][0][0] == 'a':
+                    # The file was marked as deleted in the active
+                    # state, and it is now deleted in the basis state,
+                    # so just remove the record entirely
+                    del self._dirblocks[block_index][1][entry_index]
+                else:
+                    # The basis entry needs to be marked deleted
+                    entry[1][1] = null
+                # If we are deleting a directory, we need to make sure
+                # that all of its children are already deleted
+                block_i, entry_i, d_present, f_present = \
+                    self._get_block_entry_index(old_path, '', 0)
+                if d_present:
+                    # The dir block is still present in the dirstate; this could
+                    # be due to it being in a parent tree, or a corrupt delta.
+                    for child_entry in self._dirblocks[block_i][1]:
+                        if child_entry[1][1][0] not in ('r', 'a'):
+                            self._changes_aborted = True
+                            raise errors.InconsistentDelta(old_path, entry[0][2],
+                                "The file id was deleted but its children were "
+                                "not deleted.")
             else:
                 if entry[1][0][0] == 'a':
                     self._changes_aborted = True
@@ -1740,6 +1765,7 @@
                     del self._dirblocks[block_index][1][entry_index]
                 else:
                     # it is being resurrected here, so blank it out temporarily.
+                    # should be equivalent to entry[1][1] = null
                     self._dirblocks[block_index][1][entry_index][1][1] = null
 
     def _after_delta_check_parents(self, parents, index):

=== modified file 'bzrlib/tests/test_inv.py'
--- a/bzrlib/tests/test_inv.py	2011-05-13 12:51:05 +0000
+++ b/bzrlib/tests/test_inv.py	2011-05-17 11:27:58 +0000
@@ -176,32 +176,6 @@
         # This reads basis from the repo and puts it into the tree's local
         # cache, if it has one.
         tree.set_parent_ids(['basis'])
-        paths = {}
-        parents = set()
-        for old, new, id, entry in delta:
-            if None in (new, entry):
-                continue
-            paths[new] = (entry.file_id, entry.kind)
-            parents.add(osutils.dirname(new))
-        parents = osutils.minimum_path_selection(parents)
-        parents.discard('')
-        # Put place holders in the tree to permit adding the other entries.
-        for pos, parent in enumerate(parents):
-            if not tree.path2id(parent):
-                # add a synthetic directory in the tree so we can can put the
-                # tree0 entries in place for dirstate.
-                tree.add([parent], ["id%d" % pos], ["directory"])
-        if paths:
-            # Many deltas may cause this mini-apply to fail, but we want to see what
-            # the delta application code says, not the prep that we do to deal with 
-            # limitations of dirstate's update_basis code.
-            for path, (file_id, kind) in sorted(paths.items()):
-                try:
-                    tree.add([path], [file_id], [kind])
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    pass
     finally:
         tree.unlock()
     # Fresh lock, reads disk again.
@@ -586,8 +560,41 @@
         self.assertRaises(errors.InconsistentDelta, self.apply_delta, self,
             inv, delta)
 
-
-class TestInventory(TestCase):
+    def test_add_file(self):
+        inv = self.get_empty_inventory()
+        file1 = inventory.InventoryFile('file-id', 'path', inv.root.file_id)
+        file1.revision = 'result'
+        file1.text_size = 0
+        file1.text_sha1 = ''
+        delta = [(None, u'path', 'file-id', file1)]
+        res_inv = self.apply_delta(self, inv, delta)
+        self.assertEqual('file-id', res_inv['file-id'].file_id)
+
+    def test_remove_file(self):
+        inv = self.get_empty_inventory()
+        file1 = inventory.InventoryFile('file-id', 'path', inv.root.file_id)
+        file1.revision = 'result'
+        file1.text_size = 0
+        file1.text_sha1 = ''
+        inv.add(file1)
+        delta = [(u'path', None, 'file-id', None)]
+        res_inv = self.apply_delta(self, inv, delta)
+        self.assertEqual(None, res_inv.path2id('path'))
+        self.assertRaises(errors.NoSuchId, res_inv.id2path, 'file-id')
+
+    def test_rename_file(self):
+        inv = self.get_empty_inventory()
+        file1 = inventory.InventoryFile('file-id', 'path', inv.root.file_id)
+        file1.revision = 'result'
+        file1.text_size = 0
+        file1.text_sha1 = ''
+        inv.add(file1)
+        file2 = file1.copy()
+        file2.name = 'path2'
+        delta = [(u'path', 'path2', 'file-id', file2)]
+        res_inv = self.apply_delta(self, inv, delta)
+        self.assertEqual(None, res_inv.path2id('path'))
+        self.assertEqual('file-id', res_inv.path2id('path2'))
 
     def test_is_root(self):
         """Ensure our root-checking code is accurate."""

=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- a/doc/en/release-notes/bzr-2.4.txt	2011-05-17 10:30:37 +0000
+++ b/doc/en/release-notes/bzr-2.4.txt	2011-05-17 17:31:51 +0000
@@ -83,6 +83,12 @@
   reporting subdirectories that were tree references (in formats that
   supported them). (John Arbash Meinel, #764677)
 
+* ``WT.update_basis_by_delta`` no longer requires that the deltas match
+  the current WT state. This allows ``update_basis_by_delta`` to be used
+  by more commands than just commit. Updating with a delta allows us to
+  not load the whole inventory, which can take 10+s with large trees.
+  (Jonathan Riddell, John Arbash Meinel, #781168)
+
 
 Documentation
 *************




More information about the bazaar-commits mailing list