changeset 9820:0b999aec64e8

bundle: don't send too many changesets (Issue1704) The fast path in changegroupsubset can send too many csets. This happens because it uses the parents of all bases as common nodes and then goes forward from this again. If a base has a parent that has another child, which is -not- a base, then this other child will nevertheless end up in the changegroup. The fix is to not use findmissing(), but use nodesbetween() instead, as do the slow path and incoming/outgoing. The change to test-notify.out is correct, because it actually hits this bug, as can be seen by glog'ing the two repos: @ 22c88 |\ | o 0a184 | | o | 0647d |/ o cb9a9 and o 0647d | @ cb9a9 It used to pull 0647d again, which is unnecessary.
author Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
date Sat, 07 Nov 2009 12:28:30 +0100
parents 72d670c43f6e
children 7d2e9121ef4f
files mercurial/localrepo.py tests/test-bundle tests/test-bundle.out tests/test-notify.out
diffstat 4 files changed, 55 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/localrepo.py	Sun Nov 08 18:08:24 2009 +0100
+++ b/mercurial/localrepo.py	Sat Nov 07 12:28:30 2009 +0100
@@ -1564,7 +1564,8 @@
 
         if revs is None:
             # use the fast path, no race possible on push
-            cg = self._changegroup(common.keys(), 'push')
+            nodes = self.changelog.findmissing(common.keys())
+            cg = self._changegroup(nodes, 'push')
         else:
             cg = self.changegroupsubset(update, revs, 'push')
         return cg, remote_heads
@@ -1622,28 +1623,26 @@
         the linkrev.
         """
 
+        # Set up some initial variables
+        # Make it easy to refer to self.changelog
+        cl = self.changelog
+        # msng is short for missing - compute the list of changesets in this
+        # changegroup.
+        if not bases:
+            bases = [nullid]
+        msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
+
         if extranodes is None:
             # can we go through the fast path ?
             heads.sort()
             allheads = self.heads()
             allheads.sort()
             if heads == allheads:
-                common = []
-                # parents of bases are known from both sides
-                for n in bases:
-                    for p in self.changelog.parents(n):
-                        if p != nullid:
-                            common.append(p)
-                return self._changegroup(common, source)
+                return self._changegroup(msng_cl_lst, source)
 
+        # slow path
         self.hook('preoutgoing', throw=True, source=source)
 
-        # Set up some initial variables
-        # Make it easy to refer to self.changelog
-        cl = self.changelog
-        # msng is short for missing - compute the list of changesets in this
-        # changegroup.
-        msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads)
         self.changegroupinfo(msng_cl_lst, source)
         # Some bases may turn out to be superfluous, and some heads may be
         # too.  nodesbetween will return the minimal set of bases and heads
@@ -1903,7 +1902,7 @@
         # to avoid a race we use changegroupsubset() (issue1320)
         return self.changegroupsubset(basenodes, self.heads(), source)
 
-    def _changegroup(self, common, source):
+    def _changegroup(self, nodes, source):
         """Compute the changegroup of all nodes that we have that a recipient
         doesn't.  Return a chunkbuffer object whose read() method will return
         successive changegroup chunks.
@@ -1911,12 +1910,11 @@
         This is much easier than the previous function as we can assume that
         the recipient has any changenode we aren't sending them.
 
-        common is the set of common nodes between remote and self"""
+        nodes is the set of nodes to send"""
 
         self.hook('preoutgoing', throw=True, source=source)
 
         cl = self.changelog
-        nodes = cl.findmissing(common)
         revset = set([cl.rev(n) for n in nodes])
         self.changegroupinfo(nodes, source)
 
--- a/tests/test-bundle	Sun Nov 08 18:08:24 2009 +0100
+++ b/tests/test-bundle	Sat Nov 07 12:28:30 2009 +0100
@@ -146,4 +146,23 @@
 hg -R ../all.hg diff -r tip
 cd ..
 
+echo "====== bundle single branch"
+hg init branchy
+cd branchy
+echo a >a
+hg ci -Ama
+echo b >b
+hg ci -Amb
+echo b1 >b1
+hg ci -Amb1
+hg up 0
+echo c >c
+hg ci -Amc
+echo c1 >c1
+hg ci -Amc1
+hg clone -q .#tip part
+echo "== bundling via incoming"
+hg in -R part --bundle incoming.hg --template "{node}\n" .
+echo "== bundling"
+hg bundle bundle.hg part --debug
 
--- a/tests/test-bundle.out	Sun Nov 08 18:08:24 2009 +0100
+++ b/tests/test-bundle.out	Sat Nov 07 12:28:30 2009 +0100
@@ -326,3 +326,23 @@
 -1
 -2
 -3
+====== bundle single branch
+adding a
+adding b
+adding b1
+0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+adding c
+created new head
+adding c1
+== bundling via incoming
+comparing with .
+searching for changes
+d2ae7f538514cd87c17547b0de4cea71fe1af9fb
+5ece8e77363e2b5269e27c66828b72da29e4341a
+== bundling
+searching for changes
+common changesets up to c0025332f9ed
+2 changesets found
+list of changesets:
+d2ae7f538514cd87c17547b0de4cea71fe1af9fb
+5ece8e77363e2b5269e27c66828b72da29e4341a
--- a/tests/test-notify.out	Sun Nov 08 18:08:24 2009 +0100
+++ b/tests/test-notify.out	Sat Nov 07 12:28:30 2009 +0100
@@ -174,7 +174,7 @@
 adding changesets
 adding manifests
 adding file changes
-added 2 changesets with 0 changes to 1 files
+added 2 changesets with 0 changes to 0 files
 Content-Type: text/plain; charset="us-ascii"
 MIME-Version: 1.0
 Content-Transfer-Encoding: 7bit