Rev 4046: (robertc) Create a clean method for cloning a branch and optimise the in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Wed Feb 25 05:15:43 GMT 2009


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

------------------------------------------------------------
revno: 4046
revision-id: pqm at pqm.ubuntu.com-20090225051539-61fkvmey7t598fzs
parent: pqm at pqm.ubuntu.com-20090225025839-qzk3lo9bipdwf7cj
parent: robertc at robertcollins.net-20090225042842-jwojup508avng2hc
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2009-02-25 05:15:39 +0000
message:
  (robertc) Create a clean method for cloning a branch and optimise the
  	specific case of clone-to-RemoteBranch to avoid round trips
  	reopening a branch we just created. (Robert Collins)
added:
  bzrlib/tests/branch_implementations/test_create_clone.py test_create_clone.py-20090225031440-8ybpkzojo7cvourv-1
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/push.py                 push.py-20080606021927-5fe39050e8xne9un-1
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
  bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
    ------------------------------------------------------------
    revno: 4044.1.3
    revision-id: robertc at robertcollins.net-20090225042842-jwojup508avng2hc
    parent: robertc at robertcollins.net-20090225042748-l0n1e8v5osu8dgd8
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: push.roundtrips
    timestamp: Wed 2009-02-25 15:28:42 +1100
    message:
      Create a one-shot cache of the result of RemoteBzrDir.create_branch, eliminating 3 round trips for nonstacked branches and 5 for stacked.
    modified:
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
    ------------------------------------------------------------
    revno: 4044.1.2
    revision-id: robertc at robertcollins.net-20090225042748-l0n1e8v5osu8dgd8
    parent: robertc at robertcollins.net-20090225032212-odesl979bcnjrk3f
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: push.roundtrips
    timestamp: Wed 2009-02-25 15:27:48 +1100
    message:
      Reinstate the TODO comment about bzrdir.clone_on_transport.
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
    ------------------------------------------------------------
    revno: 4044.1.1
    revision-id: robertc at robertcollins.net-20090225032212-odesl979bcnjrk3f
    parent: pqm at pqm.ubuntu.com-20090225011157-xn0w5zux5mrges6j
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: push.roundtrips
    timestamp: Wed 2009-02-25 14:22:12 +1100
    message:
      Create Branch.create_clone_on_transport helper method to combine bzr and branch creation for push.
    added:
      bzrlib/tests/branch_implementations/test_create_clone.py test_create_clone.py-20090225031440-8ybpkzojo7cvourv-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/push.py                 push.py-20080606021927-5fe39050e8xne9un-1
      bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
=== modified file 'NEWS'
--- a/NEWS	2009-02-24 10:31:49 +0000
+++ b/NEWS	2009-02-25 03:22:12 +0000
@@ -99,6 +99,9 @@
     * ``bzrlib.tests.run_suite`` accepts a runner_class parameter
       supporting the use of different runners. (Robert Collins)
 
+    * New branch method ``create_clone_on_transport`` that returns a
+      branch object. (Robert Collins)
+
     * New hook Commands['extend_command'] to allow plugins to access a
       command object before the command is run (or help generated from
       it), without overriding the command. (Robert Collins)

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-02-24 08:47:58 +0000
+++ b/bzrlib/branch.py	2009-02-25 04:27:48 +0000
@@ -916,6 +916,9 @@
     def clone(self, to_bzrdir, revision_id=None):
         """Clone this branch into to_bzrdir preserving all semantic values.
 
+        Most API users will want 'create_clone_on_transport', which creates a
+        new bzrdir and branch on the fly.
+
         revision_id: if not None, the revision history in the new branch will
                      be truncated to end with revision_id.
         """
@@ -1036,6 +1039,21 @@
             format.set_branch_format(self._format)
         return format
 
+    def create_clone_on_transport(self, to_transport, revision_id=None,
+        stacked_on=None):
+        """Create a clone of this branch and its bzrdir.
+
+        :param to_transport: The transport to clone onto.
+        :param revision_id: The revision id to use as tip in the new branch.
+            If None the tip is obtained from this branch.
+        :param stacked_on: An optional URL to stack the clone on.
+        """
+        # XXX: Fix the bzrdir API to allow getting the branch back from the
+        # clone call. Or something. 20090224 RBC/spiv.
+        dir_to = self.bzrdir.clone_on_transport(to_transport,
+            revision_id=revision_id, stacked_on=stacked_on)
+        return dir_to.open_branch()
+
     def create_checkout(self, to_location, revision_id=None,
                         lightweight=False, accelerator_tree=None,
                         hardlink=False):

=== modified file 'bzrlib/push.py'
--- a/bzrlib/push.py	2009-02-24 08:09:17 +0000
+++ b/bzrlib/push.py	2009-02-25 03:22:12 +0000
@@ -101,11 +101,8 @@
         # Now the target directory exists, but doesn't have a .bzr
         # directory. So we need to create it, along with any work to create
         # all of the dependent branches, etc.
-        dir_to = br_from.bzrdir.clone_on_transport(to_transport,
+        br_to = br_from.create_clone_on_transport(to_transport,
             revision_id=revision_id, stacked_on=stacked_on)
-        # XXX: Fix this API to allow getting the branch back from the clone
-        # call. Or something. 20090224 RBC/spiv.
-        br_to = dir_to.open_branch()
         # TODO: Some more useful message about what was copied
         try:
             finally_stacked_on = br_to.get_stacked_on_url()

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2009-02-25 00:31:09 +0000
+++ b/bzrlib/remote.py	2009-02-25 04:28:42 +0000
@@ -96,6 +96,9 @@
         # this object holds a delegated bzrdir that uses file-level operations
         # to talk to the other side
         self._real_bzrdir = None
+        # 1-shot cache for the call pattern 'create_branch; open_branch' - see
+        # create_branch for details.
+        self._next_open_branch_result = None
 
         if _client is None:
             medium = transport.get_smart_medium()
@@ -123,6 +126,12 @@
     def _translate_error(self, err, **context):
         _translate_error(err, bzrdir=self, **context)
 
+    def break_lock(self):
+        # Prevent aliasing problems in the next_open_branch_result cache.
+        # See create_branch for rationale.
+        self._next_open_branch_result = None
+        return BzrDir.break_lock(self)
+
     def cloning_metadir(self, stacked=False):
         self._ensure_real()
         return self._real_bzrdir.cloning_metadir(stacked)
@@ -146,14 +155,23 @@
         # be parameterised.
         real_branch = self._format.get_branch_format().initialize(self)
         if not isinstance(real_branch, RemoteBranch):
-            return RemoteBranch(self, self.find_repository(), real_branch)
+            result = RemoteBranch(self, self.find_repository(), real_branch)
         else:
-            return real_branch
+            result = real_branch
+        # BzrDir.clone_on_transport() uses the result of create_branch but does
+        # not return it to its callers; we save approximately 8% of our round
+        # trips by handing the branch we created back to the first caller to
+        # open_branch rather than probing anew. Long term we need a API in
+        # bzrdir that doesn't discard result objects (like result_branch).
+        # RBC 20090225
+        self._next_open_branch_result = result
+        return result
 
     def destroy_branch(self):
         """See BzrDir.destroy_branch"""
         self._ensure_real()
         self._real_bzrdir.destroy_branch()
+        self._next_open_branch_result = None
 
     def create_workingtree(self, revision_id=None, from_branch=None):
         raise errors.NotLocalUrl(self.transport.base)
@@ -187,6 +205,11 @@
     def open_branch(self, _unsupported=False):
         if _unsupported:
             raise NotImplementedError('unsupported flag support not implemented yet.')
+        if self._next_open_branch_result is not None:
+            # See create_branch for details.
+            result = self._next_open_branch_result
+            self._next_open_branch_result = None
+            return result
         reference_url = self.get_branch_reference()
         if reference_url is None:
             # branch at this location.

=== modified file 'bzrlib/tests/blackbox/test_push.py'
--- a/bzrlib/tests/blackbox/test_push.py	2009-02-24 21:22:43 +0000
+++ b/bzrlib/tests/blackbox/test_push.py	2009-02-25 04:28:42 +0000
@@ -202,7 +202,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(32, rpc_count)
+        self.assertEqual(29, rpc_count)
 
     def test_push_smart_stacked_streaming_acceptance(self):
         self.setup_smart_server_with_call_log()
@@ -219,7 +219,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(61, rpc_count)
+        self.assertEqual(56, rpc_count)
         remote = Branch.open('public')
         self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
 

=== modified file 'bzrlib/tests/branch_implementations/__init__.py'
--- a/bzrlib/tests/branch_implementations/__init__.py	2009-02-23 15:29:35 +0000
+++ b/bzrlib/tests/branch_implementations/__init__.py	2009-02-25 03:22:12 +0000
@@ -156,6 +156,7 @@
         'bzrlib.tests.branch_implementations.test_break_lock',
         'bzrlib.tests.branch_implementations.test_check',
         'bzrlib.tests.branch_implementations.test_create_checkout',
+        'bzrlib.tests.branch_implementations.test_create_clone',
         'bzrlib.tests.branch_implementations.test_commit',
         'bzrlib.tests.branch_implementations.test_dotted_revno_to_revision_id',
         'bzrlib.tests.branch_implementations.test_get_revision_id_to_revno_map',

=== added file 'bzrlib/tests/branch_implementations/test_create_clone.py'
--- a/bzrlib/tests/branch_implementations/test_create_clone.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_create_clone.py	2009-02-25 03:22:12 +0000
@@ -0,0 +1,56 @@
+# Copyright (C) 2009 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Tests for branch.create_clone behaviour."""
+
+from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
+
+
+class TestCreateClone(TestCaseWithBranch):
+
+    def test_create_clone_on_transport_no_revision_id(self):
+        tree = self.make_branch_and_tree('source')
+        tree.commit('a commit')
+        source = tree.branch
+        target_transport = self.get_transport('target')
+        result = tree.branch.create_clone_on_transport(target_transport)
+        self.assertEqual(source.last_revision(), result.last_revision())
+
+    def test_create_clone_on_transport_revision_id(self):
+        tree = self.make_branch_and_tree('source')
+        old_revid = tree.commit('a commit')
+        source_tip = tree.commit('a second commit')
+        source = tree.branch
+        target_transport = self.get_transport('target')
+        result = tree.branch.create_clone_on_transport(target_transport,
+            revision_id=old_revid)
+        self.assertEqual(old_revid, result.last_revision())
+        result.lock_read()
+        self.addCleanup(result.unlock)
+        self.assertFalse(result.repository.has_revision(source_tip))
+
+    def test_create_clone_on_transport_stacked(self):
+        tree = self.make_branch_and_tree('source')
+        tree.commit('a commit')
+        trunk = tree.branch.create_clone_on_transport(
+            self.get_transport('trunk'))
+        revid = tree.commit('a second commit')
+        source = tree.branch
+        target_transport = self.get_transport('target')
+        result = tree.branch.create_clone_on_transport(target_transport,
+            stacked_on=trunk.base)
+        self.assertEqual(revid, result.last_revision())
+        self.assertEqual(trunk.base, result.get_stacked_on_url())




More information about the bazaar-commits mailing list