Rev 3777: Teach CommitBuilder to accumulate inventory deltas. in http://people.ubuntu.com/~robertc/baz2.0/commit-delta
Robert Collins
robertc at robertcollins.net
Mon Oct 13 05:32:34 BST 2008
At http://people.ubuntu.com/~robertc/baz2.0/commit-delta
------------------------------------------------------------
revno: 3777
revision-id: robertc at robertcollins.net-20081013043229-dn4s7hfg6h6zcobm
parent: robertc at robertcollins.net-20081013002817-xxxsr37afvuhbzdx
committer: Robert Collins <robertc at robertcollins.net>
branch nick: commit-delta
timestamp: Mon 2008-10-13 15:32:29 +1100
message:
Teach CommitBuilder to accumulate inventory deltas.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/tests/per_repository/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
=== modified file 'NEWS'
--- a/NEWS 2008-10-13 00:28:17 +0000
+++ b/NEWS 2008-10-13 04:32:29 +0000
@@ -18,6 +18,11 @@
allows adding an inventory via an inventory delta, which can be
more efficient for some repository types. (Robert Collins)
+ * Repository ``CommitBuilder`` objects can now accumulate an inventory
+ delta. To enable this functionality call ``builder.recording_deletes``
+ and additionally call ``builder.record_delete`` when a delete
+ against the basis occurs. (Robert Collins)
+
bzr 1.8rc1 2008-10-07
---------------------
=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py 2008-10-13 00:28:17 +0000
+++ b/bzrlib/repository.py 2008-10-13 04:32:29 +0000
@@ -116,6 +116,8 @@
self._generate_revision_if_needed()
self.__heads = graph.HeadsCache(repository.get_graph()).heads
+ self.basis_delta = []
+ self._recording_deletes = False
def commit(self, message):
"""Make the actual commit.
@@ -211,15 +213,43 @@
"""Get a delta against the basis inventory for ie."""
if ie.file_id not in basis_inv:
# add
- return (None, path, ie.file_id, ie)
+ result = (None, path, ie.file_id, ie)
+ self.basis_delta.append(result)
+ return result
elif ie != basis_inv[ie.file_id]:
# common but altered
# TODO: avoid tis id2path call.
- return (basis_inv.id2path(ie.file_id), path, ie.file_id, ie)
+ result = (basis_inv.id2path(ie.file_id), path, ie.file_id, ie)
+ self.basis_delta.append(result)
+ return result
else:
# common, unaltered
return None
+ def record_delete(self, path, file_id):
+ """Record that a delete occured against a basis tree.
+
+ This is an optional API - when used it adds items to the basis_delta
+ being accumulated by the commit builder. It cannot be called unless the
+ method recording_deletes() has been called to inform the builder that a
+ delta is being supplied.
+
+ :param path: The path of the thing deleted.
+ :param file_id: The file id that was deleted.
+ """
+ if not self._recording_deletes:
+ raise AssertionError("recording deletes not activated.")
+ self.basis_delta.append((path, None, file_id, None))
+
+ def recording_deletes(self):
+ """Tell the commit builder that deletes are being notified.
+
+ This enables the accumulation of an inventory delta; for the resulting
+ commit to be valid deletes against the basis MUST be recorded via
+ builder.record_delete().
+ """
+ self._recording_deletes = True
+
def record_entry_contents(self, ie, parent_invs, path, tree,
content_summary):
"""Record the content of ie from tree into the commit if needed.
@@ -277,15 +307,19 @@
if ie.revision is not None:
if not self._versioned_root and path == '':
# repositories that do not version the root set the root's
- # revision to the new commit even when no change occurs, and
- # this masks when a change may have occurred against the basis,
- # so calculate if one happened.
+ # revision to the new commit even when no change occurs (more
+ # specifically, they do not record a revision on the root; and
+ # the rev id is assigned to the root during deserialisation -
+ # this masks when a change may have occurred against the basis.
+ # To match this we always issue a delta, because the revision
+ # of the root will always be changing.
if ie.file_id in basis_inv:
delta = (basis_inv.id2path(ie.file_id), path,
ie.file_id, ie)
else:
# add
delta = (None, path, ie.file_id, ie)
+ self.basis_delta.append(delta)
return delta, False, None
else:
# we don't need to commit this, because the caller already
=== modified file 'bzrlib/tests/per_repository/test_commit_builder.py'
--- a/bzrlib/tests/per_repository/test_commit_builder.py 2008-09-22 05:15:20 +0000
+++ b/bzrlib/tests/per_repository/test_commit_builder.py 2008-10-13 04:32:29 +0000
@@ -162,6 +162,7 @@
self.assertEqual(
('', '', ie.file_id, ie),
delta)
+ self.assertEqual(delta, builder.basis_delta[-1])
else:
self.assertEqual(None, delta)
# Directories do not get hashed.
@@ -191,6 +192,57 @@
# but thats all the current contract guarantees anyway.
self.assertEqual(rev_id, tree.branch.repository.get_inventory(rev_id).revision_id)
+ def test_record_delete(self):
+ tree = self.make_branch_and_tree(".")
+ self.build_tree(["foo"])
+ tree.add(["foo"], ["foo-id"])
+ rev_id = tree.commit("added foo")
+ # Remove the inventory details for foo-id, because
+ # record_entry_contents ends up copying root verbatim.
+ tree.unversion(["foo-id"])
+ tree.lock_write()
+ try:
+ basis = tree.branch.repository.revision_tree(rev_id)
+ builder = tree.branch.get_commit_builder([rev_id])
+ try:
+ builder.recording_deletes()
+ if builder.record_root_entry is True:
+ parent_invs = [basis.inventory]
+ del basis.inventory.root.children['foo']
+ builder.record_entry_contents(basis.inventory.root,
+ parent_invs, '', tree, tree.path_content_summary(''))
+ builder.record_delete("foo", "foo-id")
+ self.assertEqual(("foo", None, "foo-id", None),
+ builder.basis_delta[-1])
+ builder.finish_inventory()
+ rev_id2 = builder.commit('delete foo')
+ except:
+ tree.branch.repository.abort_write_group()
+ raise
+ finally:
+ tree.unlock()
+ rev_tree = builder.revision_tree()
+ rev_tree.lock_read()
+ self.addCleanup(rev_tree.unlock)
+ self.assertFalse(rev_tree.path2id('foo'))
+
+ def test_record_delete_without_notification(self):
+ tree = self.make_branch_and_tree(".")
+ self.build_tree(["foo"])
+ tree.add(["foo"], ["foo-id"])
+ rev_id = tree.commit("added foo")
+ tree.lock_write()
+ try:
+ builder = tree.branch.get_commit_builder([rev_id])
+ try:
+ self.record_root(builder, tree)
+ self.assertRaises(AssertionError,
+ builder.record_delete, "foo", "foo-id")
+ finally:
+ tree.branch.repository.abort_write_group()
+ finally:
+ tree.unlock()
+
def test_revision_tree(self):
tree = self.make_branch_and_tree(".")
tree.lock_write()
@@ -424,6 +476,7 @@
new_entry = builder.new_inventory[file_id]
if delta_against_basis:
expected_delta = (name, new_name, file_id, new_entry)
+ self.assertEqual(expected_delta, builder.basis_delta[-1])
else:
expected_delta = None
self.assertEqual(expected_delta, delta)
More information about the bazaar-commits
mailing list