[PATCH 8 of 8] discovery: avoid discovery when local graph is a subset of remote

Peter Arrenbrecht peter.arrenbrecht at gmail.com
Tue Mar 22 10:27:36 CDT 2011


# HG changeset patch
# User Peter Arrenbrecht <peter.arrenbrecht at gmail.com>
# Date 1300782612 -3600
discovery: avoid discovery when local graph is a subset of remote

Immediately sends local's heads to the server to check whether the server knows them all.
If it does, we can call getbundle immediately.

Interesting test output changes are:

-  added 1 changesets with 0 changes to 1 files (+1 heads)
+  added 1 changesets with 0 changes to 0 files (+1 heads)

-> The new getbundle() actually fixes a bug vs. changegroupsubset() in that it no longer
returns unnecessary files when file revs are reused.

warning: repository is unrelated
+  requesting all changes

-> The new use of common instead of bases correctly indicates that an unrelated pull
gets all changes from the server.

diff --git a/hgext/transplant.py b/hgext/transplant.py
--- a/hgext/transplant.py
+++ b/hgext/transplant.py
@@ -548,8 +548,8 @@
     if source:
         sourcerepo = ui.expandpath(source)
         source = hg.repository(ui, sourcerepo)
-        source, incoming, bundle = bundlerepo.getremotechanges(ui, repo, source,
-                                    force=True)
+        source, common, incoming, bundle = bundlerepo.getremotechanges(ui, repo,
+                                            source, force=True)
     else:
         source = repo
 
diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -286,15 +286,17 @@
         repopath, bundlename = parentpath, path
     return bundlerepository(ui, repopath, bundlename)
 
-def getremotechanges(ui, repo, other, revs=None, bundlename=None, force=False):
-    tmp = discovery.findcommonincoming(repo, other, heads=revs, force=force)
+def getremotechanges(ui, repo, other, revs=None, bundlename=None,
+                     force=False, usecommon=False):
+    tmp = discovery.findcommonincoming(repo, other, heads=revs, force=force,
+                                       commononly=usecommon)
     common, incoming, rheads = tmp
     if not incoming:
         try:
             os.unlink(bundlename)
         except:
             pass
-        return other, None, None
+        return other, None, None, None
 
     bundle = None
     if bundlename or not other.local():
@@ -303,7 +305,9 @@
         if revs is None and other.capable('changegroupsubset'):
             revs = rheads
 
-        if revs is None:
+        if usecommon:
+            cg = other.getbundle('incoming', common=common, heads=revs)
+        elif revs is None:
             cg = other.changegroup(incoming, "incoming")
         else:
             cg = other.changegroupsubset(incoming, revs, 'incoming')
@@ -315,5 +319,5 @@
         if not other.local():
             # use the created uncompressed bundlerepo
             other = bundlerepository(ui, repo.root, fname)
-    return (other, incoming, bundle)
+    return (other, common, incoming, bundle)
 
diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -9,9 +9,10 @@
 from i18n import _
 import util, error
 
-def findcommonincoming(repo, remote, heads=None, force=False):
-    """Return a tuple (common, missing roots, heads) used to identify
-    missing nodes from remote.
+def findcommonincoming(repo, remote, heads=None, force=False, commononly=False):
+    """Return a tuple (common, missing, heads) used to identify missing nodes
+    from remote. "missing" is either a boolean indicating if any nodes are missing
+    (when commononly=True), or else a list of the root nodes of the missing set.
 
     If a list of heads is specified, return only nodes which are heads
     or ancestors of these heads.
@@ -36,6 +37,13 @@
     # and start by examining the heads
     repo.ui.status(_("searching for changes\n"))
 
+    if commononly:
+        myheads = repo.heads()
+        known = remote.known(myheads)
+        if util.all(known):
+            hasincoming = set(heads).difference(set(myheads)) and True
+            return myheads, hasincoming, heads
+
     unknown = []
     for h in heads:
         if h not in m:
diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -436,14 +436,19 @@
 
     if revs:
         revs = [other.lookup(rev) for rev in revs]
-    other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
-                                opts["bundle"], opts["force"])
-    if incoming is None:
+    usecommon = other.capable('getbundle')
+    other, common, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other,
+                                       revs, opts["bundle"], opts["force"],
+                                       usecommon=usecommon)
+    if not incoming:
         ui.status(_("no changes found\n"))
         return subreporecurse()
 
     try:
-        chlist = other.changelog.nodesbetween(incoming, revs)[0]
+        if usecommon:
+            chlist = other.changelog.findmissing(common, revs)
+        else:
+            chlist = other.changelog.nodesbetween(incoming, revs)[0]
         displayer = cmdutil.show_changeset(ui, other, opts, buffered)
 
         # XXX once graphlog extension makes it into core,
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1325,20 +1325,24 @@
     def pull(self, remote, heads=None, force=False):
         lock = self.lock()
         try:
+            usecommon = remote.capable('getbundle')
             tmp = discovery.findcommonincoming(self, remote, heads=heads,
-                                               force=force)
+                                               force=force, commononly=usecommon)
             common, fetch, rheads = tmp
             if not fetch:
                 self.ui.status(_("no changes found\n"))
                 result = 0
             else:
-                if heads is None and fetch == [nullid]:
+                if heads is None and list(common) == [nullid]:
                     self.ui.status(_("requesting all changes\n"))
                 elif heads is None and remote.capable('changegroupsubset'):
                     # issue1320, avoid a race if remote changed after discovery
                     heads = rheads
 
-                if heads is None:
+                if usecommon:
+                    cg = remote.getbundle('pull', common=common,
+                                          heads=heads or rheads)
+                elif heads is None:
                     cg = remote.changegroup(fetch, 'pull')
                 elif not remote.capable('changegroupsubset'):
                     raise util.Abort(_("partial pull cannot be done because "
diff --git a/tests/test-586.t b/tests/test-586.t
--- a/tests/test-586.t
+++ b/tests/test-586.t
@@ -17,6 +17,7 @@
   pulling from ../a
   searching for changes
   warning: repository is unrelated
+  requesting all changes
   adding changesets
   adding manifests
   adding file changes
@@ -66,6 +67,7 @@
   pulling from ../repob
   searching for changes
   warning: repository is unrelated
+  requesting all changes
   adding changesets
   adding manifests
   adding file changes
diff --git a/tests/test-globalopts.t b/tests/test-globalopts.t
--- a/tests/test-globalopts.t
+++ b/tests/test-globalopts.t
@@ -28,6 +28,7 @@
   pulling from ../b
   searching for changes
   warning: repository is unrelated
+  requesting all changes
   adding changesets
   adding manifests
   adding file changes
diff --git a/tests/test-http-clone-r.t b/tests/test-http-clone-r.t
--- a/tests/test-http-clone-r.t
+++ b/tests/test-http-clone-r.t
@@ -214,7 +214,7 @@
   adding changesets
   adding manifests
   adding file changes
-  added 1 changesets with 0 changes to 1 files (+1 heads)
+  added 1 changesets with 0 changes to 0 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg verify
   checking changesets
@@ -238,7 +238,7 @@
   adding changesets
   adding manifests
   adding file changes
-  added 2 changesets with 0 changes to 1 files (+1 heads)
+  added 2 changesets with 0 changes to 0 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg verify
   checking changesets
diff --git a/tests/test-http-proxy.t b/tests/test-http-proxy.t
--- a/tests/test-http-proxy.t
+++ b/tests/test-http-proxy.t
@@ -103,18 +103,18 @@
   * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
-  * - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+  * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
-  * - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+  * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
-  * - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+  * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
-  * - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+  * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 HTTP/1.1" - - (glob)
   * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
 
diff --git a/tests/test-schemes.t b/tests/test-schemes.t
--- a/tests/test-schemes.t
+++ b/tests/test-schemes.t
@@ -29,6 +29,7 @@
   comparing with parts://localhost
   sending heads command
   searching for changes
+  sending known command
   no changes found
   [1]
 
diff --git a/tests/test-ssh-clone-r.t b/tests/test-ssh-clone-r.t
--- a/tests/test-ssh-clone-r.t
+++ b/tests/test-ssh-clone-r.t
@@ -232,7 +232,7 @@
   adding changesets
   adding manifests
   adding file changes
-  added 1 changesets with 0 changes to 1 files (+1 heads)
+  added 1 changesets with 0 changes to 0 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg verify
   checking changesets
@@ -256,7 +256,7 @@
   adding changesets
   adding manifests
   adding file changes
-  added 2 changesets with 0 changes to 1 files (+1 heads)
+  added 2 changesets with 0 changes to 0 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg verify
   checking changesets
diff --git a/tests/test-unrelated-pull.t b/tests/test-unrelated-pull.t
--- a/tests/test-unrelated-pull.t
+++ b/tests/test-unrelated-pull.t
@@ -23,6 +23,7 @@
   pulling from ../a
   searching for changes
   warning: repository is unrelated
+  requesting all changes
   adding changesets
   adding manifests
   adding file changes


More information about the Mercurial-devel mailing list