Mercurial > evolve
comparison hgext/hgfastobs.py @ 814:e629a4f9d498
fastobs: move the extension to the hgext dir
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Thu, 27 Feb 2014 17:11:09 -0800 |
parents | hgfastobs.py@ad2060da7ffa |
children | 916bebf91c41 |
comparison
equal
deleted
inserted
replaced
813:b49a9276ec8e | 814:e629a4f9d498 |
---|---|
1 """Extension to try and speed up transfer of obsolete markers. | |
2 | |
3 Mercurial 2.6 transfers obsolete markers in the dumbest way possible: | |
4 it simply transfers all of them to the server on every | |
5 operation. While this /works/, it's not ideal because it's a large | |
6 amount of extra data for users to pull down (1.9M for the 17k obsolete | |
7 markers in hg-crew as of this writing in late July 2013). It's also | |
8 frustrating because this transfer takes a nontrivial amount of time. | |
9 | |
10 You can specify a strategy with the config knob | |
11 obsolete.syncstrategy. Current strategies are "stock" and | |
12 "boxfill". Default strategy is presently boxfill. | |
13 | |
14 :stock: use the default strategy of mercurial explaned above | |
15 | |
16 :boxfill: transmit obsolete markers which list any of transmitted changesets as | |
17 a successor (transitively), as well as any kill markers for dead | |
18 nodes descended from any of the precursors of outgoing.missing. | |
19 | |
20 TODO(durin42): consider better names for sync strategies. | |
21 """ | |
22 import sys | |
23 | |
24 from mercurial import base85 | |
25 from mercurial import commands | |
26 from mercurial import extensions | |
27 from mercurial import node | |
28 from mercurial import obsolete | |
29 from mercurial import exchange | |
30 from mercurial import revset | |
31 from mercurial.i18n import _ | |
32 | |
33 _strategies = { | |
34 'stock': exchange._pushobsolete, | |
35 } | |
36 | |
37 def _strategy(name, default=False): | |
38 def inner(func): | |
39 _strategies[name] = func | |
40 if default: | |
41 _strategies[None] = func | |
42 return func | |
43 return inner | |
44 | |
45 def _pushobsoletewrapper(orig, pushop): | |
46 stratfn = _strategies[pushop.repo.ui.config('obsolete', 'syncstrategy')] | |
47 return stratfn(pushop) | |
48 | |
49 extensions.wrapfunction(exchange, '_pushobsolete', _pushobsoletewrapper) | |
50 | |
51 def _precursors(repo, s): | |
52 """Precursor of a changeset""" | |
53 cs = set() | |
54 nm = repo.changelog.nodemap | |
55 markerbysubj = repo.obsstore.precursors | |
56 for r in s: | |
57 for p in markerbysubj.get(repo[r].node(), ()): | |
58 pr = nm.get(p[0]) | |
59 if pr is not None: | |
60 cs.add(pr) | |
61 return cs | |
62 | |
63 def _revsetprecursors(repo, subset, x): | |
64 s = revset.getset(repo, revset.baseset(range(len(repo))), x) | |
65 cs = _precursors(repo, s) | |
66 return revset.baseset([r for r in subset if r in cs]) | |
67 | |
68 revset.symbols['_fastobs_precursors'] = _revsetprecursors | |
69 | |
70 | |
71 @_strategy('boxfill', default=True) | |
72 def boxfill(pushop): | |
73 """The "fill in the box" strategy from the 2.6 sprint. | |
74 | |
75 See the notes[0] from the 2.6 sprint for what "fill in the box" | |
76 means here. It's a fairly subtle algorithm, which may have | |
77 surprising behavior at times, but was the least-bad option | |
78 proposed at the sprint. | |
79 | |
80 [0]: https://bitbucket.org/durin42/2.6sprint-notes/src/tip/mercurial26-obsstore-rev.1398.txt | |
81 """ | |
82 repo = pushop.repo | |
83 remote = pushop.remote | |
84 outgoing = pushop.outgoing | |
85 urepo = pushop.repo.unfiltered() | |
86 # need to collect obsolete markers which list any of | |
87 # outgoing.missing as a successor (transitively), as well as any | |
88 # kill markers for dead nodes descended from any of the precursors | |
89 # of outgoing.missing. | |
90 boxedges = urepo.revs( | |
91 '(descendants(_fastobs_precursors(%ln)) or ' | |
92 ' descendants(%ln)) and hidden()', | |
93 outgoing.missing, outgoing.missing) | |
94 transmit = [] | |
95 for node in outgoing.missing: | |
96 transmit.extend(obsolete.precursormarkers(urepo[node])) | |
97 for node in boxedges: | |
98 transmit.extend(obsolete.successormarkers(urepo[node])) | |
99 transmit = list(set(transmit)) | |
100 xmit, total = len(transmit), len(repo.obsstore._all) | |
101 repo.ui.status( | |
102 'boxpush: about to transmit %d obsolete markers (%d markers total)\n' | |
103 % (xmit, total)) | |
104 parts, size, chunk = [], 0, 0 | |
105 def transmitmarks(): | |
106 repo.ui.note( | |
107 'boxpush: sending a chunk of obsolete markers\n') | |
108 data = ''.join([obsolete._pack('>B', obsolete._fmversion)] + parts) | |
109 remote.pushkey('obsolete', 'dump-%d' % chunk, '', | |
110 base85.b85encode(data)) | |
111 | |
112 for marker in transmit: | |
113 enc = obsolete._encodeonemarker(_markertuple(marker)) | |
114 parts.append(enc) | |
115 size += len(enc) | |
116 if size > obsolete._maxpayload: | |
117 transmitmarks() | |
118 parts, size = [], 0 | |
119 chunk += 1 | |
120 if parts: | |
121 transmitmarks() | |
122 | |
123 def _markertuple(marker): | |
124 return marker._data |