Patchwork D9801: discovery: add a devel.discovery.exchange-heads

login
register
mail settings
Submitter phabricator
Date Jan. 16, 2021, 12:27 a.m.
Message ID <differential-rev-PHID-DREV-na2p7wfzfu2fkyw7ejrs-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/48112/
State Superseded
Headers show

Comments

phabricator - Jan. 16, 2021, 12:27 a.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  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.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D9801

AFFECTED FILES
  mercurial/configitems.py
  mercurial/setdiscovery.py
  tests/test-setdiscovery.t

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/tests/test-setdiscovery.t b/tests/test-setdiscovery.t
--- a/tests/test-setdiscovery.t
+++ b/tests/test-setdiscovery.t
@@ -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
diff --git a/mercurial/setdiscovery.py b/mercurial/setdiscovery.py
--- a/mercurial/setdiscovery.py
+++ b/mercurial/setdiscovery.py
@@ -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 = False or not initial_head_exchange
     progress = ui.makeprogress(_(b'searching'), unit=_(b'queries'))
     while not disco.iscomplete():
 
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -700,6 +700,13 @@ 
     b'debug.peer-request',
     default=False,
 )
+# If discovery.exchange-heads is False, the discovery will not start but 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(