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.
This commit is contained in:
Peter Arrenbrecht 2011-03-23 16:06:55 +01:00
parent 6646f48826
commit 8f2d068a05
12 changed files with 51 additions and 25 deletions

View File

@ -548,8 +548,8 @@ def transplant(ui, repo, *revs, **opts):
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

View File

@ -286,15 +286,17 @@ def instance(ui, path, create):
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 @@ def getremotechanges(ui, repo, other, revs=None, bundlename=None, force=False):
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 @@ def getremotechanges(ui, repo, other, revs=None, bundlename=None, force=False):
if not other.local():
# use the created uncompressed bundlerepo
other = bundlerepository(ui, repo.root, fname)
return (other, incoming, bundle)
return (other, common, incoming, bundle)

View File

@ -9,9 +9,10 @@ from node import nullid, short
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 @@ def findcommonincoming(repo, remote, heads=None, force=False):
# 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:

View File

@ -436,14 +436,19 @@ def _incoming(displaychlist, subreporecurse, ui, repo, source,
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,

View File

@ -1325,20 +1325,24 @@ class localrepository(repo.repository):
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 "

View File

@ -17,6 +17,7 @@ dirstate
pulling from ../a
searching for changes
warning: repository is unrelated
requesting all changes
adding changesets
adding manifests
adding file changes
@ -66,6 +67,7 @@ create test repos
pulling from ../repob
searching for changes
warning: repository is unrelated
requesting all changes
adding changesets
adding manifests
adding file changes

View File

@ -28,6 +28,7 @@
pulling from ../b
searching for changes
warning: repository is unrelated
requesting all changes
adding changesets
adding manifests
adding file changes

View File

@ -214,7 +214,7 @@ clone remote via stream
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 @@ clone remote via stream
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

View File

@ -103,18 +103,18 @@ do not use the proxy if it is in the no list
* - - [*] "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)

View File

@ -29,6 +29,7 @@ check that {1} syntax works
comparing with parts://localhost
sending heads command
searching for changes
sending known command
no changes found
[1]

View File

@ -232,7 +232,7 @@ clone remote via stream
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 @@ clone remote via stream
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

View File

@ -23,6 +23,7 @@
pulling from ../a
searching for changes
warning: repository is unrelated
requesting all changes
adding changesets
adding manifests
adding file changes