Rev 4074: Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips. in http://people.ubuntu.com/~robertc/baz2.0/branch.roundtrips

Robert Collins robertc at robertcollins.net
Tue Mar 3 05:50:58 GMT 2009


At http://people.ubuntu.com/~robertc/baz2.0/branch.roundtrips

------------------------------------------------------------
revno: 4074
revision-id: robertc at robertcollins.net-20090303055055-0g2rfypt83bapygo
parent: robertc at robertcollins.net-20090303032751-ubyfhezgjul6y5ic
committer: Robert Collins <robertc at robertcollins.net>
branch nick: branch.roundtrips
timestamp: Tue 2009-03-03 16:50:55 +1100
message:
  Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-03-03 01:06:25 +0000
+++ b/bzrlib/branch.py	2009-03-03 05:50:55 +0000
@@ -892,7 +892,7 @@
         return  result
 
     @needs_read_lock
-    def sprout(self, to_bzrdir, revision_id=None):
+    def sprout(self, to_bzrdir, revision_id=None, repository_policy=None):
         """Create a new line of development from the branch, into to_bzrdir.
 
         to_bzrdir controls the branch format.
@@ -901,6 +901,8 @@
                      be truncated to end with revision_id.
         """
         result = to_bzrdir.create_branch()
+        if repository_policy is not None:
+            repository_policy.configure_branch(result)
         self.copy_content_into(result, revision_id=revision_id)
         result.set_parent(self.bzrdir.root_transport.base)
         return result

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py	2009-03-03 03:27:51 +0000
+++ b/bzrlib/bzrdir.py	2009-03-03 05:50:55 +0000
@@ -1126,17 +1126,9 @@
             # Not especially, but it's part of the contract.
             result_branch = result.create_branch()
         else:
-            # Force NULL revision to avoid using repository before stacking
-            # is configured.
-            result_branch = source_branch.sprout(
-                result, revision_id=_mod_revision.NULL_REVISION)
-            parent_location = result_branch.get_parent()
+            result_branch = source_branch.sprout(result,
+                revision_id=revision_id, repository_policy=repository_policy)
         mutter("created new branch %r" % (result_branch,))
-        repository_policy.configure_branch(result_branch)
-        if source_branch is not None:
-            source_branch.copy_content_into(result_branch, revision_id)
-            # Override copy_content_into
-            result_branch.set_parent(parent_location)
 
         # Create/update the result working tree
         if (create_tree_if_local and

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2009-03-01 11:11:14 +0000
+++ b/bzrlib/tests/__init__.py	2009-03-03 05:50:55 +0000
@@ -1820,6 +1820,29 @@
         return sio
 
 
+class CapturedCall(object):
+    """A helper for capturing smart server calls for easy debug analysis."""
+
+    def __init__(self, params, prefix_length):
+        """Capture the call with params and skip prefix_length stack frames."""
+        self.call = params
+        import traceback
+        # The last 5 frames are the __init__, the hook frame, and 3 smart
+        # client frames. Beyond this we could get more clever, but this is good
+        # enough for now.
+        stack = traceback.extract_stack()[prefix_length:-5]
+        self.stack = ''.join(traceback.format_list(stack))
+
+    def __str__(self):
+        return self.call.method
+
+    def __repr__(self):
+        return self.call.method
+
+    def stack(self):
+        return self.stack
+
+
 class TestCaseWithMemoryTransport(TestCase):
     """Common test class for tests that do not need disk resources.
 
@@ -2116,9 +2139,13 @@
         """Sets up a smart server as the transport server with a call log."""
         self.transport_server = server.SmartTCPServer_for_testing
         self.hpss_calls = []
+        import traceback
+        # Skip the current stack down to the caller of
+        # setup_smart_server_with_call_log
+        prefix_length = len(traceback.extract_stack()) - 2
         def capture_hpss_call(params):
-            import traceback
-            self.hpss_calls.append((params, traceback.format_stack()))
+            self.hpss_calls.append(
+                CapturedCall(params, prefix_length))
         client._SmartClient.hooks.install_named_hook(
             'call', capture_hpss_call, None)
 

=== modified file 'bzrlib/tests/blackbox/test_branch.py'
--- a/bzrlib/tests/blackbox/test_branch.py	2009-03-03 03:27:51 +0000
+++ b/bzrlib/tests/blackbox/test_branch.py	2009-03-03 05:50:55 +0000
@@ -273,7 +273,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertEqual(95, rpc_count)
+        self.assertEqual(71, rpc_count)
 
     def test_branch_from_trivial_branch_streaming_acceptance(self):
         self.setup_smart_server_with_call_log()
@@ -289,7 +289,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertEqual(21, rpc_count)
+        self.assertEqual(17, rpc_count)
 
 
 class TestRemoteBranch(TestCaseWithSFTPServer):

=== modified file 'bzrlib/tests/branch_implementations/test_sprout.py'
--- a/bzrlib/tests/branch_implementations/test_sprout.py	2009-02-24 05:37:17 +0000
+++ b/bzrlib/tests/branch_implementations/test_sprout.py	2009-03-03 05:50:55 +0000
@@ -19,6 +19,7 @@
 import os
 from bzrlib import (
     branch as _mod_branch,
+    errors,
     remote,
     revision as _mod_revision,
     tests,
@@ -151,3 +152,36 @@
             raise KnownFailure('there is no support for'
                                ' symlinks to non-ASCII targets (bug #272444)')
 
+    def assertBranchHookBranchIsStacked(self, pre_change_params):
+        # Just calling will either succeed or fail.
+        pre_change_params.branch.get_stacked_on_url()
+        self.hook_calls.append(pre_change_params)
+
+    def test_sprout_stacked_hooks_get_stacked_branch(self):
+        tree = self.make_branch_and_tree('source')
+        tree.commit('a commit')
+        revid = tree.commit('a second commit')
+        source = tree.branch
+        target_transport = self.get_transport('target')
+        self.hook_calls = []
+        _mod_branch.Branch.hooks.install_named_hook("pre_change_branch_tip",
+            self.assertBranchHookBranchIsStacked, None)
+        try:
+            dir = source.bzrdir.sprout(target_transport.base,
+                source.last_revision(), possible_transports=[target_transport],
+                source_branch=source, stacked=True)
+        except errors.UnstackableBranchFormat:
+            if isinstance(self.branch_format, _mod_branch.BzrBranchFormat4):
+                raise KnownFailure("Format 4 doesn't auto stack successfully.")
+            else:
+                raise
+        result = dir.open_branch()
+        self.assertEqual(revid, result.last_revision())
+        self.assertEqual(source.base, result.get_stacked_on_url())
+        # Smart servers invoke hooks on both sides
+        if isinstance(result, remote.RemoteBranch):
+            expected_calls = 2
+        else:
+            expected_calls = 1
+        self.assertEqual(expected_calls, len(self.hook_calls))
+

=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py	2009-03-03 03:27:51 +0000
+++ b/bzrlib/tests/test_remote.py	2009-03-03 05:50:55 +0000
@@ -359,7 +359,7 @@
         self.disable_verb(verb)
         format = a_dir.cloning_metadir()
         call_count = len([call for call in self.hpss_calls if
-            call[0].method == verb])
+            call.call.method == verb])
         self.assertEqual(1, call_count)
 
     def test_current_server(self):
@@ -516,7 +516,7 @@
         self.disable_verb('BzrDir.create_branch')
         branch = repo.bzrdir.create_branch()
         create_branch_call_count = len([call for call in self.hpss_calls if
-            call[0].method == 'BzrDir.create_branch'])
+            call.call.method == 'BzrDir.create_branch'])
         self.assertEqual(1, create_branch_call_count)
 
     def test_current_server(self):
@@ -552,7 +552,7 @@
         self.disable_verb('BzrDir.create_repository')
         repo = bzrdir.create_repository()
         create_repo_call_count = len([call for call in self.hpss_calls if
-            call[0].method == 'BzrDir.create_repository'])
+            call.call.method == 'BzrDir.create_repository'])
         self.assertEqual(1, create_repo_call_count)
 
     def test_current_server(self):
@@ -1632,7 +1632,7 @@
         self.disable_verb(verb)
         repo.set_make_working_trees(True)
         call_count = len([call for call in self.hpss_calls if
-            call[0].method == verb])
+            call.call.method == verb])
         self.assertEqual(1, call_count)
 
     def test_current(self):




More information about the bazaar-commits mailing list