diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -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( 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 = not initial_head_exchange progress = ui.makeprogress(_(b'searching'), unit=_(b'queries')) while not disco.iscomplete(): 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