##// END OF EJS Templates
exchangev2: fetch and apply phases data...
Gregory Szorc -
r39669:ff2de4f2 default
parent child Browse files
Show More
@@ -1,138 +1,167 b''
1 1 # exchangev2.py - repository exchange for wire protocol version 2
2 2 #
3 3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import weakref
11 11
12 12 from .i18n import _
13 13 from .node import (
14 14 nullid,
15 15 short,
16 16 )
17 17 from . import (
18 18 mdiff,
19 phases,
19 20 pycompat,
20 21 setdiscovery,
21 22 )
22 23
23 24 def pull(pullop):
24 25 """Pull using wire protocol version 2."""
25 26 repo = pullop.repo
26 27 remote = pullop.remote
27 28 tr = pullop.trmanager.transaction()
28 29
29 30 # Figure out what needs to be fetched.
30 31 common, fetch, remoteheads = _pullchangesetdiscovery(
31 32 repo, remote, pullop.heads, abortwhenunrelated=pullop.force)
32 33
34 # And fetch the data.
33 35 pullheads = pullop.heads or remoteheads
34 _fetchchangesets(repo, tr, remote, common, fetch, pullheads)
36 csetres = _fetchchangesets(repo, tr, remote, common, fetch, pullheads)
37
38 # New revisions are written to the changelog. But all other updates
39 # are deferred. Do those now.
40
41 # Ensure all new changesets are draft by default. If the repo is
42 # publishing, the phase will be adjusted by the loop below.
43 if csetres['added']:
44 phases.registernew(repo, tr, phases.draft, csetres['added'])
45
46 # And adjust the phase of all changesets accordingly.
47 for phase in phases.phasenames:
48 if phase == b'secret' or not csetres['nodesbyphase'][phase]:
49 continue
50
51 phases.advanceboundary(repo, tr, phases.phasenames.index(phase),
52 csetres['nodesbyphase'][phase])
35 53
36 54 def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True):
37 55 """Determine which changesets need to be pulled."""
38 56
39 57 if heads:
40 58 knownnode = repo.changelog.hasnode
41 59 if all(knownnode(head) for head in heads):
42 60 return heads, False, heads
43 61
44 62 # TODO wire protocol version 2 is capable of more efficient discovery
45 63 # than setdiscovery. Consider implementing something better.
46 64 common, fetch, remoteheads = setdiscovery.findcommonheads(
47 65 repo.ui, repo, remote, abortwhenunrelated=abortwhenunrelated)
48 66
49 67 common = set(common)
50 68 remoteheads = set(remoteheads)
51 69
52 70 # If a remote head is filtered locally, put it back in the common set.
53 71 # See the comment in exchange._pulldiscoverychangegroup() for more.
54 72
55 73 if fetch and remoteheads:
56 74 nodemap = repo.unfiltered().changelog.nodemap
57 75
58 76 common |= {head for head in remoteheads if head in nodemap}
59 77
60 78 if set(remoteheads).issubset(common):
61 79 fetch = []
62 80
63 81 common.discard(nullid)
64 82
65 83 return common, fetch, remoteheads
66 84
67 85 def _fetchchangesets(repo, tr, remote, common, fetch, remoteheads):
68 if not fetch:
69 return
70
71 86 # TODO consider adding a step here where we obtain the DAG shape first
72 87 # (or ask the server to slice changesets into chunks for us) so that
73 88 # we can perform multiple fetches in batches. This will facilitate
74 89 # resuming interrupted clones, higher server-side cache hit rates due
75 90 # to smaller segments, etc.
76 91 with remote.commandexecutor() as e:
77 92 objs = e.callcommand(b'changesetdata', {
78 93 b'noderange': [sorted(common), sorted(remoteheads)],
79 b'fields': {b'parents', b'revision'},
94 b'fields': {b'parents', b'phase', b'revision'},
80 95 }).result()
81 96
82 97 # The context manager waits on all response data when exiting. So
83 98 # we need to remain in the context manager in order to stream data.
84 99 return _processchangesetdata(repo, tr, objs)
85 100
86 101 def _processchangesetdata(repo, tr, objs):
87 102 repo.hook('prechangegroup', throw=True,
88 103 **pycompat.strkwargs(tr.hookargs))
89 104
90 105 urepo = repo.unfiltered()
91 106 cl = urepo.changelog
92 107
93 108 cl.delayupdate(tr)
94 109
95 110 # The first emitted object is a header describing the data that
96 111 # follows.
97 112 meta = next(objs)
98 113
99 114 progress = repo.ui.makeprogress(_('changesets'),
100 115 unit=_('chunks'),
101 116 total=meta.get(b'totalitems'))
102 117
103 118 def linkrev(node):
104 119 repo.ui.debug('add changeset %s\n' % short(node))
105 120 # Linkrev for changelog is always self.
106 121 return len(cl)
107 122
108 123 def onchangeset(cl, node):
109 124 progress.increment()
110 125
126 nodesbyphase = {phase: set() for phase in phases.phasenames}
127
111 128 # addgroup() expects a 7-tuple describing revisions. This normalizes
112 129 # the wire data to that format.
130 #
131 # This loop also aggregates non-revision metadata, such as phase
132 # data.
113 133 def iterrevisions():
114 134 for cset in objs:
115 assert b'revisionsize' in cset
135 node = cset[b'node']
136
137 if b'phase' in cset:
138 nodesbyphase[cset[b'phase']].add(node)
139
140 # Some entries might only be metadata only updates.
141 if b'revisionsize' not in cset:
142 continue
143
116 144 data = next(objs)
117 145
118 146 yield (
119 cset[b'node'],
147 node,
120 148 cset[b'parents'][0],
121 149 cset[b'parents'][1],
122 150 # Linknode is always itself for changesets.
123 151 cset[b'node'],
124 152 # We always send full revisions. So delta base is not set.
125 153 nullid,
126 154 mdiff.trivialdiffheader(len(data)) + data,
127 155 # Flags not yet supported.
128 156 0,
129 157 )
130 158
131 159 added = cl.addgroup(iterrevisions(), linkrev, weakref.proxy(tr),
132 160 addrevisioncb=onchangeset)
133 161
134 162 progress.complete()
135 163
136 164 return {
137 165 'added': added,
166 'nodesbyphase': nodesbyphase,
138 167 }
@@ -1,214 +1,277 b''
1 1 Tests for wire protocol version 2 exchange.
2 2 Tests in this file should be folded into existing tests once protocol
3 3 v2 has enough features that it can be enabled via #testcase in existing
4 4 tests.
5 5
6 6 $ . $TESTDIR/wireprotohelpers.sh
7 7 $ enablehttpv2client
8 8
9 9 $ hg init server-simple
10 10 $ enablehttpv2 server-simple
11 11 $ cd server-simple
12 12 $ cat >> .hg/hgrc << EOF
13 13 > [phases]
14 14 > publish = false
15 15 > EOF
16 16 $ echo a0 > a
17 17 $ echo b0 > b
18 18 $ hg -q commit -A -m 'commit 0'
19 19
20 20 $ echo a1 > a
21 21 $ hg commit -m 'commit 1'
22 22 $ hg phase --public -r .
23 23 $ echo a2 > a
24 24 $ hg commit -m 'commit 2'
25 25
26 26 $ hg -q up -r 0
27 27 $ echo b1 > b
28 28 $ hg -q commit -m 'head 2 commit 1'
29 29 $ echo b2 > b
30 30 $ hg -q commit -m 'head 2 commit 2'
31 31
32 32 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
33 33 $ cat hg.pid > $DAEMON_PIDS
34 34
35 35 $ cd ..
36 36
37 37 Test basic clone
38 38
39 39 $ hg --debug clone -U http://localhost:$HGPORT client-simple
40 40 using http://localhost:$HGPORT/
41 41 sending capabilities command
42 42 query 1; heads
43 43 sending 2 commands
44 44 sending command heads: {}
45 45 sending command known: {
46 46 'nodes': []
47 47 }
48 48 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
49 49 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
50 50 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
51 51 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
52 52 received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
53 53 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
54 54 sending 1 commands
55 55 sending command changesetdata: {
56 56 'fields': set([
57 57 'parents',
58 'phase',
58 59 'revision'
59 60 ]),
60 61 'noderange': [
61 62 [],
62 63 [
63 64 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
64 65 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
65 66 ]
66 67 ]
67 68 }
68 69 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
69 received frame(size=809; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
70 received frame(size=871; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
70 71 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
71 72 add changeset 3390ef850073
72 73 add changeset 4432d83626e8
73 74 add changeset cd2534766bec
74 75 add changeset e96ae20f4188
75 76 add changeset caa2a465451d
76 77 updating the branch cache
77 new changesets 3390ef850073:caa2a465451d
78 new changesets 3390ef850073:caa2a465451d (3 drafts)
78 79
79 80 All changesets should have been transferred
80 81
81 82 $ hg -R client-simple debugindex -c
82 83 rev linkrev nodeid p1 p2
83 84 0 0 3390ef850073 000000000000 000000000000
84 85 1 1 4432d83626e8 3390ef850073 000000000000
85 86 2 2 cd2534766bec 4432d83626e8 000000000000
86 87 3 3 e96ae20f4188 3390ef850073 000000000000
87 88 4 4 caa2a465451d e96ae20f4188 000000000000
88 89
89 90 $ hg -R client-simple log -G -T '{rev} {node} {phase}\n'
90 o 4 caa2a465451dd1facda0f5b12312c355584188a1 public
91 o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft
91 92 |
92 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 public
93 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
93 94 |
94 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f public
95 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
95 96 | |
96 97 | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
97 98 |/
98 99 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
99 100
100 101
101 102 Cloning only a specific revision works
102 103
103 104 $ hg --debug clone -U -r 4432d83626e8 http://localhost:$HGPORT client-singlehead
104 105 using http://localhost:$HGPORT/
105 106 sending capabilities command
106 107 sending 1 commands
107 108 sending command lookup: {
108 109 'key': '4432d83626e8'
109 110 }
110 111 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
111 112 received frame(size=21; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
112 113 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
113 114 query 1; heads
114 115 sending 2 commands
115 116 sending command heads: {}
116 117 sending command known: {
117 118 'nodes': []
118 119 }
119 120 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
120 121 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
121 122 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
122 123 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
123 124 received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
124 125 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
125 126 sending 1 commands
126 127 sending command changesetdata: {
127 128 'fields': set([
128 129 'parents',
130 'phase',
129 131 'revision'
130 132 ]),
131 133 'noderange': [
132 134 [],
133 135 [
134 136 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
135 137 ]
136 138 ]
137 139 }
138 140 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
139 received frame(size=327; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
141 received frame(size=353; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
140 142 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
141 143 add changeset 3390ef850073
142 144 add changeset 4432d83626e8
143 145 updating the branch cache
144 146 new changesets 3390ef850073:4432d83626e8
145 147
146 148 $ cd client-singlehead
147 149
148 150 $ hg log -G -T '{rev} {node} {phase}\n'
149 151 o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
150 152 |
151 153 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
152 154
153 155
154 156 Incremental pull works
155 157
156 158 $ hg --debug pull
157 159 pulling from http://localhost:$HGPORT/
158 160 using http://localhost:$HGPORT/
159 161 sending capabilities command
160 162 query 1; heads
161 163 sending 2 commands
162 164 sending command heads: {}
163 165 sending command known: {
164 166 'nodes': [
165 167 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
166 168 ]
167 169 }
168 170 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
169 171 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
170 172 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
171 173 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
172 174 received frame(size=2; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
173 175 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
174 176 searching for changes
175 177 all local heads known remotely
176 178 sending 1 commands
177 179 sending command changesetdata: {
178 180 'fields': set([
179 181 'parents',
182 'phase',
180 183 'revision'
181 184 ]),
182 185 'noderange': [
183 186 [
184 187 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
185 188 ],
186 189 [
187 190 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
188 191 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
189 192 ]
190 193 ]
191 194 }
192 195 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
193 received frame(size=495; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
196 received frame(size=571; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
194 197 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
195 198 add changeset cd2534766bec
196 199 add changeset e96ae20f4188
197 200 add changeset caa2a465451d
198 201 updating the branch cache
199 new changesets cd2534766bec:caa2a465451d
202 new changesets cd2534766bec:caa2a465451d (3 drafts)
203 (run 'hg update' to get a working copy)
204
205 $ hg log -G -T '{rev} {node} {phase}\n'
206 o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft
207 |
208 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
209 |
210 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
211 | |
212 | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
213 |/
214 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
215
216
217 Phase-only update works
218
219 $ hg -R ../server-simple phase --public -r caa2a465451dd
220 $ hg --debug pull
221 pulling from http://localhost:$HGPORT/
222 using http://localhost:$HGPORT/
223 sending capabilities command
224 query 1; heads
225 sending 2 commands
226 sending command heads: {}
227 sending command known: {
228 'nodes': [
229 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
230 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
231 ]
232 }
233 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
234 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
235 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
236 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
237 received frame(size=3; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
238 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
239 searching for changes
240 all remote heads known locally
241 sending 1 commands
242 sending command changesetdata: {
243 'fields': set([
244 'parents',
245 'phase',
246 'revision'
247 ]),
248 'noderange': [
249 [
250 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
251 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
252 ],
253 [
254 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
255 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
256 ]
257 ]
258 }
259 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
260 received frame(size=92; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
261 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
262 2 local changesets published
200 263 (run 'hg update' to get a working copy)
201 264
202 265 $ hg log -G -T '{rev} {node} {phase}\n'
203 266 o 4 caa2a465451dd1facda0f5b12312c355584188a1 public
204 267 |
205 268 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 public
206 269 |
207 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f public
270 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
208 271 | |
209 272 | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
210 273 |/
211 274 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
212 275
213 276
214 277 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now