setdiscover: allow to ignore part of the local graph
Currently, the push discovery first determines the full set of common nodes
before looking into what changesets are outgoing. When pushing a specific
subset, this can lead to pathological situations where we search for the status
of thousand of local heads that are unrelated to the requested pushes.
To fix this, we need to teach the discovery to ignores part of the graph. Most
of the necessary pieces were already in place. This changeset just makes them
available to higher level API and tests them.
Change actually impacting pushes are coming in a later changeset.
--- a/mercurial/dagutil.py Thu Dec 07 01:53:14 2017 +0100
+++ b/mercurial/dagutil.py Wed Dec 06 22:44:51 2017 +0100
@@ -154,8 +154,9 @@
class revlogdag(revlogbaseddag):
'''dag interface to a revlog'''
- def __init__(self, revlog):
+ def __init__(self, revlog, localsubset=None):
revlogbaseddag.__init__(self, revlog, set(revlog))
+ self._heads = localsubset
def _getheads(self):
return [r for r in self._revlog.headrevs() if r != nullrev]
--- a/mercurial/debugcommands.py Thu Dec 07 01:53:14 2017 +0100
+++ b/mercurial/debugcommands.py Wed Dec 06 22:44:51 2017 +0100
@@ -734,6 +734,7 @@
[('', 'old', None, _('use old-style discovery')),
('', 'nonheads', None,
_('use old-style discovery with non-heads included')),
+ ('', 'rev', [], 'restrict discovery to this set of revs'),
] + cmdutil.remoteopts,
_('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
def debugdiscovery(ui, repo, remoteurl="default", **opts):
@@ -747,11 +748,8 @@
# make sure tests are repeatable
random.seed(12323)
- def doit(localheads, remoteheads, remote=remote):
+ def doit(pushedrevs, remoteheads, remote=remote):
if opts.get('old'):
- if localheads:
- raise error.Abort('cannot use localheads with old style '
- 'discovery')
if not util.safehasattr(remote, 'branches'):
# enable in-client legacy support
remote = localrepo.locallegacypeer(remote.local())
@@ -765,7 +763,12 @@
all = dag.ancestorset(dag.internalizeall(common))
common = dag.externalizeall(dag.headsetofconnecteds(all))
else:
- common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
+ nodes = None
+ if pushedrevs:
+ revs = scmutil.revrange(repo, pushedrevs)
+ nodes = [repo[r].node() for r in revs]
+ common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
+ ancestorsof=nodes)
common = set(common)
rheads = set(hds)
lheads = set(repo.heads())
@@ -794,7 +797,7 @@
else:
remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
opts.get('remote_head'))
- localrevs = opts.get('local_head')
+ localrevs = opts.get('rev')
doit(localrevs, remoterevs)
@command('debugextensions', cmdutil.formatteropts, [], norepo=True)
--- a/mercurial/setdiscovery.py Thu Dec 07 01:53:14 2017 +0100
+++ b/mercurial/setdiscovery.py Wed Dec 06 22:44:51 2017 +0100
@@ -133,7 +133,8 @@
def findcommonheads(ui, local, remote,
initialsamplesize=100,
fullsamplesize=200,
- abortwhenunrelated=True):
+ abortwhenunrelated=True,
+ ancestorsof=None):
'''Return a tuple (common, anyincoming, remoteheads) used to identify
missing nodes from or in remote.
'''
@@ -141,7 +142,11 @@
roundtrips = 0
cl = local.changelog
- dag = dagutil.revlogdag(cl)
+ localsubset = None
+ if ancestorsof is not None:
+ rev = local.changelog.rev
+ localsubset = [rev(n) for n in ancestorsof]
+ dag = dagutil.revlogdag(cl, localsubset=localsubset)
# early exit if we know all the specified remote heads already
ui.debug("query 1; heads\n")
--- a/tests/test-completion.t Thu Dec 07 01:53:14 2017 +0100
+++ b/tests/test-completion.t Wed Dec 06 22:44:51 2017 +0100
@@ -261,7 +261,7 @@
debugdate: extended
debugdeltachain: changelog, manifest, dir, template
debugdirstate: nodates, datesort
- debugdiscovery: old, nonheads, ssh, remotecmd, insecure
+ debugdiscovery: old, nonheads, rev, ssh, remotecmd, insecure
debugextensions: template
debugfileset: rev
debugfsinfo:
--- a/tests/test-setdiscovery.t Thu Dec 07 01:53:14 2017 +0100
+++ b/tests/test-setdiscovery.t Wed Dec 06 22:44:51 2017 +0100
@@ -16,11 +16,17 @@
> echo "% -- a -> b set"
> hg -R a debugdiscovery b --verbose --debug --config progress.debug=true
> echo
+ > echo "% -- a -> b set (tip only)"
+ > hg -R a debugdiscovery b --verbose --debug --config progress.debug=true --rev tip
+ > echo
> echo "% -- b -> a tree"
> hg -R b debugdiscovery a --verbose --old
> echo
> echo "% -- b -> a set"
> hg -R b debugdiscovery a --verbose --debug --config progress.debug=true
+ > echo
+ > echo "% -- b -> a set (tip only)"
+ > hg -R b debugdiscovery a --verbose --debug --config progress.debug=true --rev tip
> cd ..
> }
@@ -48,6 +54,13 @@
common heads: 01241442b3c2 b5714e113bc0
local is subset
+ % -- a -> b set (tip only)
+ comparing with b
+ query 1; heads
+ searching for changes
+ all local heads known remotely
+ common heads: b5714e113bc0
+
% -- b -> a tree
comparing with a
searching for changes
@@ -62,6 +75,14 @@
all remote heads known locally
common heads: 01241442b3c2 b5714e113bc0
remote is subset
+
+ % -- b -> a set (tip only)
+ comparing with a
+ query 1; heads
+ searching for changes
+ all remote heads known locally
+ common heads: 01241442b3c2 b5714e113bc0
+ remote is subset
Many new:
@@ -86,6 +107,16 @@
2 total queries in *.????s (glob)
common heads: bebd167eb94d
+ % -- a -> b set (tip only)
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries in *.????s (glob)
+ common heads: 66f7d451a68b
+
% -- b -> a tree
comparing with a
searching for changes
@@ -101,6 +132,16 @@
query 2; still undecided: 2, sample size is: 2
2 total queries in *.????s (glob)
common heads: bebd167eb94d
+
+ % -- b -> a set (tip only)
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking initial sample
+ searching: 2 queries
+ query 2; still undecided: 2, sample size is: 2
+ 2 total queries in *.????s (glob)
+ common heads: bebd167eb94d
Both sides many new with stub:
@@ -124,6 +165,16 @@
2 total queries in *.????s (glob)
common heads: 2dc09a01254d
+ % -- a -> b set (tip only)
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries in *.????s (glob)
+ common heads: 66f7d451a68b
+
% -- b -> a tree
comparing with a
searching for changes
@@ -139,6 +190,16 @@
query 2; still undecided: 29, sample size is: 29
2 total queries in *.????s (glob)
common heads: 2dc09a01254d
+
+ % -- b -> a set (tip only)
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking initial sample
+ searching: 2 queries
+ query 2; still undecided: 29, sample size is: 29
+ 2 total queries in *.????s (glob)
+ common heads: 2dc09a01254d
Both many new:
@@ -163,6 +224,16 @@
2 total queries in *.????s (glob)
common heads: 66f7d451a68b
+ % -- a -> b set (tip only)
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries in *.????s (glob)
+ common heads: 66f7d451a68b
+
% -- b -> a tree
comparing with a
searching for changes
@@ -178,6 +249,16 @@
query 2; still undecided: 31, sample size is: 31
2 total queries in *.????s (glob)
common heads: 66f7d451a68b
+
+ % -- b -> a set (tip only)
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries in *.????s (glob)
+ common heads: 66f7d451a68b
Both many new skewed:
@@ -202,6 +283,16 @@
2 total queries in *.????s (glob)
common heads: 66f7d451a68b
+ % -- a -> b set (tip only)
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 51, sample size is: 51
+ 2 total queries in *.????s (glob)
+ common heads: 66f7d451a68b
+
% -- b -> a tree
comparing with a
searching for changes
@@ -217,6 +308,16 @@
query 2; still undecided: 31, sample size is: 31
2 total queries in *.????s (glob)
common heads: 66f7d451a68b
+
+ % -- b -> a set (tip only)
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 31, sample size is: 31
+ 2 total queries in *.????s (glob)
+ common heads: 66f7d451a68b
Both many new on top of long history:
@@ -244,6 +345,19 @@
3 total queries in *.????s (glob)
common heads: 7ead0cba2838
+ % -- a -> b set (tip only)
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 1049, sample size is: 11
+ sampling from both directions
+ searching: 3 queries
+ query 3; still undecided: 31, sample size is: 31
+ 3 total queries in *.????s (glob)
+ common heads: 7ead0cba2838
+
% -- b -> a tree
comparing with a
searching for changes
@@ -262,6 +376,19 @@
query 3; still undecided: 15, sample size is: 15
3 total queries in *.????s (glob)
common heads: 7ead0cba2838
+
+ % -- b -> a set (tip only)
+ comparing with a
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 1029, sample size is: 11
+ sampling from both directions
+ searching: 3 queries
+ query 3; still undecided: 15, sample size is: 15
+ 3 total queries in *.????s (glob)
+ common heads: 7ead0cba2838
One with >200 heads, which used to use up all of the sample:
@@ -327,6 +454,18 @@
query 6; still undecided: \d+, sample size is: \d+ (re)
6 total queries in *.????s (glob)
common heads: 3ee37d65064a
+ $ hg -R a debugdiscovery b --debug --verbose --config progress.debug=true --rev tip
+ comparing with b
+ query 1; heads
+ searching for changes
+ taking quick initial sample
+ searching: 2 queries
+ query 2; still undecided: 303, sample size is: 9
+ sampling from both directions
+ searching: 3 queries
+ query 3; still undecided: 3, sample size is: 3
+ 3 total queries in *.????s (glob)
+ common heads: 3ee37d65064a
Test actual protocol when pulling one new head in addition to common heads