Mercurial > evolve
comparison hgext/evolve.py @ 1244:3249814dabd1 stable
discovery: introduce a obshash1 function using fm1 during hashing (issue4587)
The 'fm0' serialisation translate float to text. This give different result
between python2.6 and python2.7 (because python2.7 got smarter). The 'fm1' is
all binary and expected to be stable so we introduce the ability to do the
discovery using hash computed with 'fm1' serialisation.
We use a new wireprotocol version (Partly because I'm too lazy to check how to add an
argument to the existing one) and capabilities).
Support in simple4server is will come in the next changeset.
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Fri, 10 Apr 2015 23:24:36 -0400 |
parents | e886bc501796 |
children | 4279ec5ff3a7 1556d8fed538 |
comparison
equal
deleted
inserted
replaced
1243:3ffa12edc05a | 1244:3249814dabd1 |
---|---|
2338 return caps | 2338 return caps |
2339 | 2339 |
2340 @eh.extsetup | 2340 @eh.extsetup |
2341 def _installobsmarkersdiscovery(ui): | 2341 def _installobsmarkersdiscovery(ui): |
2342 hgweb_mod.perms['evoext_obshash'] = 'pull' | 2342 hgweb_mod.perms['evoext_obshash'] = 'pull' |
2343 hgweb_mod.perms['evoext_obshash1'] = 'pull' | |
2343 # wrap command content | 2344 # wrap command content |
2344 oldcap, args = wireproto.commands['capabilities'] | 2345 oldcap, args = wireproto.commands['capabilities'] |
2345 def newcap(repo, proto): | 2346 def newcap(repo, proto): |
2346 return discocapabilities(oldcap, repo, proto) | 2347 return discocapabilities(oldcap, repo, proto) |
2347 wireproto.commands['capabilities'] = (newcap, args) | 2348 wireproto.commands['capabilities'] = (newcap, args) |
2348 wireproto.commands['evoext_obshash'] = (srv_obshash, 'nodes') | 2349 wireproto.commands['evoext_obshash'] = (srv_obshash, 'nodes') |
2350 wireproto.commands['evoext_obshash1'] = (srv_obshash1, 'nodes') | |
2349 if getattr(exchange, '_pushdiscoveryobsmarkers', None) is None: | 2351 if getattr(exchange, '_pushdiscoveryobsmarkers', None) is None: |
2350 ui.warn('evolve: your mercurial version is too old\n' | 2352 ui.warn('evolve: your mercurial version is too old\n' |
2351 'evolve: (running in degraded mode, push will includes all markers)\n') | 2353 'evolve: (running in degraded mode, push will includes all markers)\n') |
2352 else: | 2354 else: |
2353 olddisco = exchange.pushdiscoverymapping['obsmarker'] | 2355 olddisco = exchange.pushdiscoverymapping['obsmarker'] |
2358 ### Set discovery START | 2360 ### Set discovery START |
2359 | 2361 |
2360 from mercurial import dagutil | 2362 from mercurial import dagutil |
2361 from mercurial import setdiscovery | 2363 from mercurial import setdiscovery |
2362 | 2364 |
2363 def _obshash(repo, nodes): | 2365 def _obshash(repo, nodes, version=0): |
2364 hashs = _obsrelsethashtree(repo) | 2366 if version == 0: |
2367 hashs = _obsrelsethashtreefm0(repo) | |
2368 elif version ==1: | |
2369 hashs = _obsrelsethashtreefm1(repo) | |
2370 else: | |
2371 assert False | |
2365 nm = repo.changelog.nodemap | 2372 nm = repo.changelog.nodemap |
2366 revs = [nm.get(n) for n in nodes] | 2373 revs = [nm.get(n) for n in nodes] |
2367 return [r is None and nullid or hashs[r][1] for r in revs] | 2374 return [r is None and nullid or hashs[r][1] for r in revs] |
2368 | 2375 |
2369 def srv_obshash(repo, proto, nodes): | 2376 def srv_obshash(repo, proto, nodes): |
2370 return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes))) | 2377 return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes))) |
2371 | 2378 |
2379 def srv_obshash1(repo, proto, nodes): | |
2380 return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes), version=1)) | |
2381 | |
2372 @eh.addattr(localrepo.localpeer, 'evoext_obshash') | 2382 @eh.addattr(localrepo.localpeer, 'evoext_obshash') |
2373 def local_obshash(peer, nodes): | 2383 def local_obshash(peer, nodes): |
2374 return _obshash(peer._repo, nodes) | 2384 return _obshash(peer._repo, nodes) |
2385 | |
2386 @eh.addattr(localrepo.localpeer, 'evoext_obshash1') | |
2387 def local_obshash1(peer, nodes): | |
2388 return _obshash(peer._repo, nodes, version=1) | |
2375 | 2389 |
2376 @eh.addattr(wireproto.wirepeer, 'evoext_obshash') | 2390 @eh.addattr(wireproto.wirepeer, 'evoext_obshash') |
2377 def peer_obshash(self, nodes): | 2391 def peer_obshash(self, nodes): |
2378 d = self._call("evoext_obshash", nodes=wireproto.encodelist(nodes)) | 2392 d = self._call("evoext_obshash", nodes=wireproto.encodelist(nodes)) |
2379 try: | 2393 try: |
2380 return wireproto.decodelist(d) | 2394 return wireproto.decodelist(d) |
2381 except ValueError: | 2395 except ValueError: |
2382 self._abort(error.ResponseError(_("unexpected response:"), d)) | 2396 self._abort(error.ResponseError(_("unexpected response:"), d)) |
2383 | 2397 |
2398 @eh.addattr(wireproto.wirepeer, 'evoext_obshash1') | |
2399 def peer_obshash1(self, nodes): | |
2400 d = self._call("evoext_obshash1", nodes=wireproto.encodelist(nodes)) | |
2401 try: | |
2402 return wireproto.decodelist(d) | |
2403 except ValueError: | |
2404 self._abort(error.ResponseError(_("unexpected response:"), d)) | |
2405 | |
2384 def findcommonobsmarkers(ui, local, remote, probeset, | 2406 def findcommonobsmarkers(ui, local, remote, probeset, |
2385 initialsamplesize=100, | 2407 initialsamplesize=100, |
2386 fullsamplesize=200): | 2408 fullsamplesize=200): |
2387 # from discovery | 2409 # from discovery |
2388 roundtrips = 0 | 2410 roundtrips = 0 |
2389 cl = local.changelog | 2411 cl = local.changelog |
2390 dag = dagutil.revlogdag(cl) | 2412 dag = dagutil.revlogdag(cl) |
2391 localhash = _obsrelsethashtree(local) | |
2392 missing = set() | 2413 missing = set() |
2393 common = set() | 2414 common = set() |
2394 undecided = set(probeset) | 2415 undecided = set(probeset) |
2395 _takefullsample = setdiscovery._takefullsample | 2416 _takefullsample = setdiscovery._takefullsample |
2417 if remote.capable('_evoext_obshash_1'): | |
2418 remotehash = remote.evoext_obshash1 | |
2419 localhash = _obsrelsethashtreefm1(local) | |
2420 else: | |
2421 remotehash = remote.evoext_obshash | |
2422 localhash = _obsrelsethashtreefm0(local) | |
2396 | 2423 |
2397 while undecided: | 2424 while undecided: |
2398 | 2425 |
2399 ui.note(_("sampling from both directions\n")) | 2426 ui.note(_("sampling from both directions\n")) |
2400 if len(undecided) < fullsamplesize: | 2427 if len(undecided) < fullsamplesize: |
2405 roundtrips += 1 | 2432 roundtrips += 1 |
2406 ui.debug("query %i; still undecided: %i, sample size is: %i\n" | 2433 ui.debug("query %i; still undecided: %i, sample size is: %i\n" |
2407 % (roundtrips, len(undecided), len(sample))) | 2434 % (roundtrips, len(undecided), len(sample))) |
2408 # indices between sample and externalized version must match | 2435 # indices between sample and externalized version must match |
2409 sample = list(sample) | 2436 sample = list(sample) |
2410 remotehash = remote.evoext_obshash(dag.externalizeall(sample)) | 2437 remotehash = remotehash(dag.externalizeall(sample)) |
2411 | 2438 |
2412 yesno = [localhash[ix][1] == remotehash[si] | 2439 yesno = [localhash[ix][1] == remotehash[si] |
2413 for si, ix in enumerate(sample)] | 2440 for si, ix in enumerate(sample)] |
2414 | 2441 |
2415 commoninsample = set(n for i, n in enumerate(sample) if yesno[i]) | 2442 commoninsample = set(n for i, n in enumerate(sample) if yesno[i]) |
2736 finaldata.write('%20i' % len(obsdata)) | 2763 finaldata.write('%20i' % len(obsdata)) |
2737 finaldata.write(obsdata) | 2764 finaldata.write(obsdata) |
2738 finaldata.seek(0) | 2765 finaldata.seek(0) |
2739 return wireproto.streamres(proto.groupchunks(finaldata)) | 2766 return wireproto.streamres(proto.groupchunks(finaldata)) |
2740 | 2767 |
2741 def _obsrelsethashtree(repo): | 2768 def _obsrelsethashtreefm0(repo): |
2769 return _obsrelsethashtree(repo, obsolete._fm0encodeonemarker) | |
2770 | |
2771 def _obsrelsethashtreefm1(repo): | |
2772 return _obsrelsethashtree(repo, obsolete._fm1encodeonemarker) | |
2773 | |
2774 def _obsrelsethashtree(repo, encodeonemarker): | |
2742 cache = [] | 2775 cache = [] |
2743 unfi = repo.unfiltered() | 2776 unfi = repo.unfiltered() |
2744 markercache = {} | 2777 markercache = {} |
2745 for i in unfi: | 2778 for i in unfi: |
2746 ctx = unfi[i] | 2779 ctx = unfi[i] |
2759 tmarkers = repo.obsstore.relevantmarkers([ctx.node()]) | 2792 tmarkers = repo.obsstore.relevantmarkers([ctx.node()]) |
2760 if tmarkers: | 2793 if tmarkers: |
2761 bmarkers = [] | 2794 bmarkers = [] |
2762 for m in tmarkers: | 2795 for m in tmarkers: |
2763 if not m in markercache: | 2796 if not m in markercache: |
2764 markercache[m] = obsolete._fm0encodeonemarker(m) | 2797 markercache[m] = encodeonemarker(m) |
2765 bmarkers.append(markercache[m]) | 2798 bmarkers.append(markercache[m]) |
2766 bmarkers.sort() | 2799 bmarkers.sort() |
2767 for m in bmarkers: | 2800 for m in bmarkers: |
2768 entry += 1 | 2801 entry += 1 |
2769 sha.update(m) | 2802 sha.update(m) |
2772 else: | 2805 else: |
2773 cache.append((ctx.node(), nullid)) | 2806 cache.append((ctx.node(), nullid)) |
2774 return cache | 2807 return cache |
2775 | 2808 |
2776 @command('debugobsrelsethashtree', | 2809 @command('debugobsrelsethashtree', |
2777 [] , _('')) | 2810 [('', 'v0', None, 'hash on marker format "0"'), |
2778 def debugobsrelsethashtree(ui, repo): | 2811 ('', 'v1', None, 'hash on marker format "1" (default)') |
2812 ,] , _('')) | |
2813 def debugobsrelsethashtree(ui, repo, v0=False, v1=False): | |
2779 """display Obsolete markers, Relevant Set, Hash Tree | 2814 """display Obsolete markers, Relevant Set, Hash Tree |
2780 changeset-node obsrelsethashtree-node | 2815 changeset-node obsrelsethashtree-node |
2781 | 2816 |
2782 It computed form the "orsht" of its parent and markers | 2817 It computed form the "orsht" of its parent and markers |
2783 relevant to the changeset itself.""" | 2818 relevant to the changeset itself.""" |
2784 for chg, obs in _obsrelsethashtree(repo): | 2819 if v0 and v1: |
2820 raise util.Abort('cannot only specify one format') | |
2821 elif v0: | |
2822 treefunc = _obsrelsethashtreefm0 | |
2823 else: | |
2824 treefunc = _obsrelsethashtreefm1 | |
2825 | |
2826 treefunc = _obsrelsethashtree | |
2827 for chg, obs in treefunc(repo): | |
2785 ui.status('%s %s\n' % (node.hex(chg), node.hex(obs))) | 2828 ui.status('%s %s\n' % (node.hex(chg), node.hex(obs))) |
2786 | 2829 |
2787 _bestformat = max(obsolete.formats.keys()) | 2830 _bestformat = max(obsolete.formats.keys()) |
2788 | 2831 |
2789 | 2832 |
2838 caps = orig(repo, proto) | 2881 caps = orig(repo, proto) |
2839 if obsolete._enabled: | 2882 if obsolete._enabled: |
2840 caps += ' _evoext_pushobsmarkers_0' | 2883 caps += ' _evoext_pushobsmarkers_0' |
2841 caps += ' _evoext_pullobsmarkers_0' | 2884 caps += ' _evoext_pullobsmarkers_0' |
2842 caps += ' _evoext_obshash_0' | 2885 caps += ' _evoext_obshash_0' |
2886 caps += ' _evoext_obshash_1' | |
2843 caps += ' _evoext_getbundle_obscommon' | 2887 caps += ' _evoext_getbundle_obscommon' |
2844 return caps | 2888 return caps |
2845 | 2889 |
2846 | 2890 |
2847 @eh.extsetup | 2891 @eh.extsetup |