discovery: add a devel.discovery.exchange-heads
authorPierre-Yves David <pierre-yves.david@octobus.net>
Sat, 16 Jan 2021 01:02:03 +0100
changeset 46316 6ee9bd69ff7f
parent 46315 2ef575c62f10
child 46317 d0225a22040c
discovery: add a devel.discovery.exchange-heads Currently all discovery start with testing local and remote heads. For analysis purpose we make it possible to disable that initial "handshake" and start discovery with the whole repository as undecided. Differential Revision: https://phab.mercurial-scm.org/D9801
mercurial/configitems.py
mercurial/setdiscovery.py
tests/test-setdiscovery.t
--- a/mercurial/configitems.py	Sun Jan 17 02:48:15 2021 +0100
+++ b/mercurial/configitems.py	Sat Jan 16 01:02:03 2021 +0100
@@ -702,6 +702,13 @@
     b'debug.peer-request',
     default=False,
 )
+# If discovery.exchange-heads is False, the discovery will not start with
+# remote head fetching and local head querying.
+coreconfigitem(
+    b'devel',
+    b'discovery.exchange-heads',
+    default=True,
+)
 # If discovery.grow-sample is False, the sample size used in set discovery will
 # not be increased through the process
 coreconfigitem(
--- a/mercurial/setdiscovery.py	Sun Jan 17 02:48:15 2021 +0100
+++ b/mercurial/setdiscovery.py	Sat Jan 16 01:02:03 2021 +0100
@@ -314,6 +314,8 @@
     else:
         ownheads = [rev for rev in cl.headrevs() if rev != nullrev]
 
+    initial_head_exchange = ui.configbool(b'devel', b'discovery.exchange-heads')
+
     # We also ask remote about all the local heads. That set can be arbitrarily
     # large, so we used to limit it size to `initialsamplesize`. We no longer
     # do as it proved counter productive. The skipped heads could lead to a
@@ -365,33 +367,39 @@
     #     graph (with many heads) attached to, but very independant to a the
     #     "simple" graph on the server. This is a fairly usual case and have
     #     not been met in the wild so far.
-    if remote.limitedarguments:
-        sample = _limitsample(ownheads, initialsamplesize)
-        # indices between sample and externalized version must match
-        sample = list(sample)
-    else:
-        sample = ownheads
+    if initial_head_exchange:
+        if remote.limitedarguments:
+            sample = _limitsample(ownheads, initialsamplesize)
+            # indices between sample and externalized version must match
+            sample = list(sample)
+        else:
+            sample = ownheads
 
-    ui.debug(b"query 1; heads\n")
-    roundtrips += 1
-    with remote.commandexecutor() as e:
-        fheads = e.callcommand(b'heads', {})
-        fknown = e.callcommand(
-            b'known',
-            {
-                b'nodes': [clnode(r) for r in sample],
-            },
-        )
+        ui.debug(b"query 1; heads\n")
+        roundtrips += 1
+        with remote.commandexecutor() as e:
+            fheads = e.callcommand(b'heads', {})
+            fknown = e.callcommand(
+                b'known',
+                {
+                    b'nodes': [clnode(r) for r in sample],
+                },
+            )
+
+        srvheadhashes, yesno = fheads.result(), fknown.result()
 
-    srvheadhashes, yesno = fheads.result(), fknown.result()
-
-    if audit is not None:
-        audit[b'total-roundtrips'] = 1
+        if audit is not None:
+            audit[b'total-roundtrips'] = 1
 
-    if cl.tip() == nullid:
-        if srvheadhashes != [nullid]:
-            return [nullid], True, srvheadhashes
-        return [nullid], False, []
+        if cl.tip() == nullid:
+            if srvheadhashes != [nullid]:
+                return [nullid], True, srvheadhashes
+            return [nullid], False, []
+    else:
+        # we still need the remote head for the function return
+        with remote.commandexecutor() as e:
+            fheads = e.callcommand(b'heads', {})
+        srvheadhashes = fheads.result()
 
     # start actual discovery (we note this before the next "if" for
     # compatibility reasons)
@@ -408,15 +416,16 @@
         except error.LookupError:
             continue
 
-    # early exit if we know all the specified remote heads already
-    if len(knownsrvheads) == len(srvheadhashes):
-        ui.debug(b"all remote heads known locally\n")
-        return srvheadhashes, False, srvheadhashes
+    if initial_head_exchange:
+        # early exit if we know all the specified remote heads already
+        if len(knownsrvheads) == len(srvheadhashes):
+            ui.debug(b"all remote heads known locally\n")
+            return srvheadhashes, False, srvheadhashes
 
-    if len(sample) == len(ownheads) and all(yesno):
-        ui.note(_(b"all local changesets known remotely\n"))
-        ownheadhashes = [clnode(r) for r in ownheads]
-        return ownheadhashes, True, srvheadhashes
+        if len(sample) == len(ownheads) and all(yesno):
+            ui.note(_(b"all local changesets known remotely\n"))
+            ownheadhashes = [clnode(r) for r in ownheads]
+            return ownheadhashes, True, srvheadhashes
 
     # full blown discovery
 
@@ -429,12 +438,13 @@
     disco = partialdiscovery(
         local, ownheads, hard_limit_sample, randomize=randomize
     )
-    # treat remote heads (and maybe own heads) as a first implicit sample
-    # response
-    disco.addcommons(knownsrvheads)
-    disco.addinfo(zip(sample, yesno))
+    if initial_head_exchange:
+        # treat remote heads (and maybe own heads) as a first implicit sample
+        # response
+        disco.addcommons(knownsrvheads)
+        disco.addinfo(zip(sample, yesno))
 
-    full = False
+    full = not initial_head_exchange
     progress = ui.makeprogress(_(b'searching'), unit=_(b'queries'))
     while not disco.iscomplete():
 
--- a/tests/test-setdiscovery.t	Sun Jan 17 02:48:15 2021 +0100
+++ b/tests/test-setdiscovery.t	Sat Jan 16 01:02:03 2021 +0100
@@ -1412,23 +1412,22 @@
       missing:                1040
   common heads: 3ee37d65064a
 
-  $ hg -R a debugdiscovery b --debug --config devel.discovery.randomize=false --config devel.discovery.grow-sample.rate=1.01
+  $ hg -R a debugdiscovery b --debug --config devel.discovery.exchange-heads=false --config devel.discovery.randomize=false --config devel.discovery.grow-sample.rate=1.01
   comparing with b
-  query 1; heads
   searching for changes
-  taking quick initial sample
-  query 2; still undecided: 1080, sample size is: 100
   sampling from both directions
-  query 3; still undecided: 980, sample size is: 200
+  query 1; still undecided: 1340, sample size is: 200
+  sampling from both directions
+  query 2; still undecided: 795, sample size is: 202
   sampling from both directions
-  query 4; still undecided: 497, sample size is: 202
+  query 3; still undecided: 525, sample size is: 204
   sampling from both directions
-  query 5; still undecided: 294, sample size is: 204
+  query 4; still undecided: 252, sample size is: 206
   sampling from both directions
-  query 6; still undecided: 90, sample size is: 90
-  6 total queries in *s (glob)
+  query 5; still undecided: 44, sample size is: 44
+  5 total queries in *s (glob)
   elapsed time: * seconds (glob)
-  round-trips:                   6
+  round-trips:                   5
   heads summary:
     total common heads:          1
       also local heads:          0