Patchwork [1,of,2] setdiscover: allow to ignore part of the local graph

login
register
mail settings
Submitter Boris Feld
Date Dec. 7, 2017, 12:32 p.m.
Message ID <f2fcdbfa1475d055caaa.1512649932@FB>
Download mbox | patch
Permalink /patch/25995/
State Accepted
Headers show

Comments

Boris Feld - Dec. 7, 2017, 12:32 p.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1512596691 -3600
#      Wed Dec 06 22:44:51 2017 +0100
# Node ID f2fcdbfa1475d055caaa44c9cc23a58284c97e4b
# Parent  15d38e8fcb1ec963584509b4ace582d9cbc04530
# EXP-Topic discovery
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r f2fcdbfa1475
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.

Patch

diff --git a/mercurial/dagutil.py b/mercurial/dagutil.py
--- a/mercurial/dagutil.py
+++ b/mercurial/dagutil.py
@@ -154,8 +154,9 @@  class revlogbaseddag(basedag):
 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]
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -734,6 +734,7 @@  def debugstate(ui, repo, **opts):
     [('', '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 @@  def debugdiscovery(ui, repo, remoteurl="
     # 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 @@  def debugdiscovery(ui, repo, remoteurl="
                 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 @@  def debugdiscovery(ui, repo, remoteurl="
     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)
diff --git a/mercurial/setdiscovery.py b/mercurial/setdiscovery.py
--- a/mercurial/setdiscovery.py
+++ b/mercurial/setdiscovery.py
@@ -133,7 +133,8 @@  def _limitsample(sample, desiredlen):
 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 @@  def findcommonheads(ui, local, remote,
 
     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")
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -261,7 +261,7 @@  Show all commands + options
   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: 
diff --git a/tests/test-setdiscovery.t b/tests/test-setdiscovery.t
--- a/tests/test-setdiscovery.t
+++ b/tests/test-setdiscovery.t
@@ -16,11 +16,17 @@  Function to test discovery between two r
   >     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 @@  Small superset:
   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 @@  Small superset:
   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 @@  Many new:
   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 @@  Many new:
   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 @@  Both sides many new with stub:
   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 @@  Both sides many new with stub:
   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 @@  Both many new:
   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 @@  Both many new:
   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 @@  Both many new skewed:
   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 @@  Both many new skewed:
   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 @@  Both many new on top of long history:
   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 @@  Both many new on top of long history:
   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 @@  One with >200 heads, which used to use u
   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