##// END OF EJS Templates
setdiscovery: return anyincoming=False when remote's only head is nullid...
Andrew Pritchard -
r14981:192e0268 stable
parent child Browse files
Show More
@@ -1,193 +1,194 b''
1 1 # setdiscovery.py - improved discovery of common nodeset for mercurial
2 2 #
3 3 # Copyright 2010 Benoit Boissinot <bboissin@gmail.com>
4 4 # and Peter Arrenbrecht <peter@arrenbrecht.ch>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from node import nullid
10 10 from i18n import _
11 11 import random, collections, util, dagutil
12 12
13 13 def _updatesample(dag, nodes, sample, always, quicksamplesize=0):
14 14 # if nodes is empty we scan the entire graph
15 15 if nodes:
16 16 heads = dag.headsetofconnecteds(nodes)
17 17 else:
18 18 heads = dag.heads()
19 19 dist = {}
20 20 visit = collections.deque(heads)
21 21 seen = set()
22 22 factor = 1
23 23 while visit:
24 24 curr = visit.popleft()
25 25 if curr in seen:
26 26 continue
27 27 d = dist.setdefault(curr, 1)
28 28 if d > factor:
29 29 factor *= 2
30 30 if d == factor:
31 31 if curr not in always: # need this check for the early exit below
32 32 sample.add(curr)
33 33 if quicksamplesize and (len(sample) >= quicksamplesize):
34 34 return
35 35 seen.add(curr)
36 36 for p in dag.parents(curr):
37 37 if not nodes or p in nodes:
38 38 dist.setdefault(p, d + 1)
39 39 visit.append(p)
40 40
41 41 def _setupsample(dag, nodes, size):
42 42 if len(nodes) <= size:
43 43 return set(nodes), None, 0
44 44 always = set(dag.heads())
45 45 desiredlen = size - len(always)
46 46 if desiredlen <= 0:
47 47 # This could be bad if there are very many heads, all unknown to the
48 48 # server. We're counting on long request support here.
49 49 return always, None, desiredlen
50 50 return always, set(), desiredlen
51 51
52 52 def _takequicksample(dag, nodes, size, initial):
53 53 always, sample, desiredlen = _setupsample(dag, nodes, size)
54 54 if sample is None:
55 55 return always
56 56 if initial:
57 57 fromset = None
58 58 else:
59 59 fromset = nodes
60 60 _updatesample(dag, fromset, sample, always, quicksamplesize=desiredlen)
61 61 sample.update(always)
62 62 return sample
63 63
64 64 def _takefullsample(dag, nodes, size):
65 65 always, sample, desiredlen = _setupsample(dag, nodes, size)
66 66 if sample is None:
67 67 return always
68 68 # update from heads
69 69 _updatesample(dag, nodes, sample, always)
70 70 # update from roots
71 71 _updatesample(dag.inverse(), nodes, sample, always)
72 72 assert sample
73 73 if len(sample) > desiredlen:
74 74 sample = set(random.sample(sample, desiredlen))
75 75 elif len(sample) < desiredlen:
76 76 more = desiredlen - len(sample)
77 77 sample.update(random.sample(list(nodes - sample - always), more))
78 78 sample.update(always)
79 79 return sample
80 80
81 81 def findcommonheads(ui, local, remote,
82 82 initialsamplesize=100,
83 83 fullsamplesize=200,
84 84 abortwhenunrelated=True):
85 85 '''Return a tuple (common, anyincoming, remoteheads) used to identify
86 86 missing nodes from or in remote.
87 87
88 88 shortcutlocal determines whether we try use direct access to localrepo if
89 89 remote is actually local.
90 90 '''
91 91 roundtrips = 0
92 92 cl = local.changelog
93 93 dag = dagutil.revlogdag(cl)
94 94
95 95 # early exit if we know all the specified remote heads already
96 96 ui.debug("query 1; heads\n")
97 97 roundtrips += 1
98 98 ownheads = dag.heads()
99 99 sample = ownheads
100 100 if remote.local():
101 101 # stopgap until we have a proper localpeer that supports batch()
102 102 srvheadhashes = remote.heads()
103 103 yesno = remote.known(dag.externalizeall(sample))
104 104 elif remote.capable('batch'):
105 105 batch = remote.batch()
106 106 srvheadhashesref = batch.heads()
107 107 yesnoref = batch.known(dag.externalizeall(sample))
108 108 batch.submit()
109 109 srvheadhashes = srvheadhashesref.value
110 110 yesno = yesnoref.value
111 111 else:
112 112 # compatibitity with pre-batch, but post-known remotes during 1.9 devel
113 113 srvheadhashes = remote.heads()
114 114 sample = []
115 115
116 116 if cl.tip() == nullid:
117 117 if srvheadhashes != [nullid]:
118 118 return [nullid], True, srvheadhashes
119 119 return [nullid], False, []
120 120
121 121 # start actual discovery (we note this before the next "if" for
122 122 # compatibility reasons)
123 123 ui.status(_("searching for changes\n"))
124 124
125 125 srvheads = dag.internalizeall(srvheadhashes, filterunknown=True)
126 126 if len(srvheads) == len(srvheadhashes):
127 127 ui.debug("all remote heads known locally\n")
128 128 return (srvheadhashes, False, srvheadhashes,)
129 129
130 130 if sample and util.all(yesno):
131 131 ui.note("all local heads known remotely\n")
132 132 ownheadhashes = dag.externalizeall(ownheads)
133 133 return (ownheadhashes, True, srvheadhashes,)
134 134
135 135 # full blown discovery
136 136 undecided = dag.nodeset() # own nodes where I don't know if remote knows them
137 137 common = set() # own nodes I know we both know
138 138 missing = set() # own nodes I know remote lacks
139 139
140 140 # treat remote heads (and maybe own heads) as a first implicit sample response
141 141 common.update(dag.ancestorset(srvheads))
142 142 undecided.difference_update(common)
143 143
144 144 full = False
145 145 while undecided:
146 146
147 147 if sample:
148 148 commoninsample = set(n for i, n in enumerate(sample) if yesno[i])
149 149 common.update(dag.ancestorset(commoninsample, common))
150 150
151 151 missinginsample = [n for i, n in enumerate(sample) if not yesno[i]]
152 152 missing.update(dag.descendantset(missinginsample, missing))
153 153
154 154 undecided.difference_update(missing)
155 155 undecided.difference_update(common)
156 156
157 157 if not undecided:
158 158 break
159 159
160 160 if full:
161 161 ui.note("sampling from both directions\n")
162 162 sample = _takefullsample(dag, undecided, size=fullsamplesize)
163 163 elif common:
164 164 # use cheapish initial sample
165 165 ui.debug("taking initial sample\n")
166 166 sample = _takefullsample(dag, undecided, size=fullsamplesize)
167 167 else:
168 168 # use even cheaper initial sample
169 169 ui.debug("taking quick initial sample\n")
170 170 sample = _takequicksample(dag, undecided, size=initialsamplesize,
171 171 initial=True)
172 172
173 173 roundtrips += 1
174 174 ui.progress(_('searching'), roundtrips, unit=_('queries'))
175 175 ui.debug("query %i; still undecided: %i, sample size is: %i\n"
176 176 % (roundtrips, len(undecided), len(sample)))
177 177 # indices between sample and externalized version must match
178 178 sample = list(sample)
179 179 yesno = remote.known(dag.externalizeall(sample))
180 180 full = True
181 181
182 182 result = dag.headsetofconnecteds(common)
183 183 ui.progress(_('searching'), None)
184 184 ui.debug("%d total queries\n" % roundtrips)
185 185
186 186 if not result and srvheadhashes != [nullid]:
187 187 if abortwhenunrelated:
188 188 raise util.Abort(_("repository is unrelated"))
189 189 else:
190 190 ui.warn(_("warning: repository is unrelated\n"))
191 191 return (set([nullid]), True, srvheadhashes,)
192 192
193 return (dag.externalizeall(result), True, srvheadhashes,)
193 anyincoming = (srvheadhashes != [nullid])
194 return dag.externalizeall(result), anyincoming, srvheadhashes
@@ -1,467 +1,480 b''
1 1 $ hg init test
2 2 $ cd test
3 3 $ for i in 0 1 2 3 4 5 6 7 8; do
4 4 > echo $i >> foo
5 5 > hg commit -A -m $i
6 6 > done
7 7 adding foo
8 8 $ hg verify
9 9 checking changesets
10 10 checking manifests
11 11 crosschecking files in changesets and manifests
12 12 checking files
13 13 1 files, 9 changesets, 9 total revisions
14 14 $ hg serve -p $HGPORT -d --pid-file=hg.pid
15 15 $ cat hg.pid >> $DAEMON_PIDS
16 16 $ cd ..
17 17
18 18 $ hg init new
19 19
20 20 http incoming
21 21
22 22 $ hg -R new incoming http://localhost:$HGPORT/
23 23 comparing with http://localhost:$HGPORT/
24 24 changeset: 0:00a43fa82f62
25 25 user: test
26 26 date: Thu Jan 01 00:00:00 1970 +0000
27 27 summary: 0
28 28
29 29 changeset: 1:5460a410df01
30 30 user: test
31 31 date: Thu Jan 01 00:00:00 1970 +0000
32 32 summary: 1
33 33
34 34 changeset: 2:d9f42cd1a1ec
35 35 user: test
36 36 date: Thu Jan 01 00:00:00 1970 +0000
37 37 summary: 2
38 38
39 39 changeset: 3:376476025137
40 40 user: test
41 41 date: Thu Jan 01 00:00:00 1970 +0000
42 42 summary: 3
43 43
44 44 changeset: 4:70d7eb252d49
45 45 user: test
46 46 date: Thu Jan 01 00:00:00 1970 +0000
47 47 summary: 4
48 48
49 49 changeset: 5:ad284ee3b5ee
50 50 user: test
51 51 date: Thu Jan 01 00:00:00 1970 +0000
52 52 summary: 5
53 53
54 54 changeset: 6:e9229f2de384
55 55 user: test
56 56 date: Thu Jan 01 00:00:00 1970 +0000
57 57 summary: 6
58 58
59 59 changeset: 7:d152815bb8db
60 60 user: test
61 61 date: Thu Jan 01 00:00:00 1970 +0000
62 62 summary: 7
63 63
64 64 changeset: 8:e4feb4ac9035
65 65 tag: tip
66 66 user: test
67 67 date: Thu Jan 01 00:00:00 1970 +0000
68 68 summary: 8
69 69
70 70 $ hg -R new incoming -r 4 http://localhost:$HGPORT/
71 71 comparing with http://localhost:$HGPORT/
72 72 changeset: 0:00a43fa82f62
73 73 user: test
74 74 date: Thu Jan 01 00:00:00 1970 +0000
75 75 summary: 0
76 76
77 77 changeset: 1:5460a410df01
78 78 user: test
79 79 date: Thu Jan 01 00:00:00 1970 +0000
80 80 summary: 1
81 81
82 82 changeset: 2:d9f42cd1a1ec
83 83 user: test
84 84 date: Thu Jan 01 00:00:00 1970 +0000
85 85 summary: 2
86 86
87 87 changeset: 3:376476025137
88 88 user: test
89 89 date: Thu Jan 01 00:00:00 1970 +0000
90 90 summary: 3
91 91
92 92 changeset: 4:70d7eb252d49
93 93 tag: tip
94 94 user: test
95 95 date: Thu Jan 01 00:00:00 1970 +0000
96 96 summary: 4
97 97
98 98
99 99 local incoming
100 100
101 101 $ hg -R new incoming test
102 102 comparing with test
103 103 changeset: 0:00a43fa82f62
104 104 user: test
105 105 date: Thu Jan 01 00:00:00 1970 +0000
106 106 summary: 0
107 107
108 108 changeset: 1:5460a410df01
109 109 user: test
110 110 date: Thu Jan 01 00:00:00 1970 +0000
111 111 summary: 1
112 112
113 113 changeset: 2:d9f42cd1a1ec
114 114 user: test
115 115 date: Thu Jan 01 00:00:00 1970 +0000
116 116 summary: 2
117 117
118 118 changeset: 3:376476025137
119 119 user: test
120 120 date: Thu Jan 01 00:00:00 1970 +0000
121 121 summary: 3
122 122
123 123 changeset: 4:70d7eb252d49
124 124 user: test
125 125 date: Thu Jan 01 00:00:00 1970 +0000
126 126 summary: 4
127 127
128 128 changeset: 5:ad284ee3b5ee
129 129 user: test
130 130 date: Thu Jan 01 00:00:00 1970 +0000
131 131 summary: 5
132 132
133 133 changeset: 6:e9229f2de384
134 134 user: test
135 135 date: Thu Jan 01 00:00:00 1970 +0000
136 136 summary: 6
137 137
138 138 changeset: 7:d152815bb8db
139 139 user: test
140 140 date: Thu Jan 01 00:00:00 1970 +0000
141 141 summary: 7
142 142
143 143 changeset: 8:e4feb4ac9035
144 144 tag: tip
145 145 user: test
146 146 date: Thu Jan 01 00:00:00 1970 +0000
147 147 summary: 8
148 148
149 149 $ hg -R new incoming -r 4 test
150 150 comparing with test
151 151 changeset: 0:00a43fa82f62
152 152 user: test
153 153 date: Thu Jan 01 00:00:00 1970 +0000
154 154 summary: 0
155 155
156 156 changeset: 1:5460a410df01
157 157 user: test
158 158 date: Thu Jan 01 00:00:00 1970 +0000
159 159 summary: 1
160 160
161 161 changeset: 2:d9f42cd1a1ec
162 162 user: test
163 163 date: Thu Jan 01 00:00:00 1970 +0000
164 164 summary: 2
165 165
166 166 changeset: 3:376476025137
167 167 user: test
168 168 date: Thu Jan 01 00:00:00 1970 +0000
169 169 summary: 3
170 170
171 171 changeset: 4:70d7eb252d49
172 172 user: test
173 173 date: Thu Jan 01 00:00:00 1970 +0000
174 174 summary: 4
175 175
176 176
177 177 limit to 2 changesets
178 178
179 179 $ hg -R new incoming -l 2 test
180 180 comparing with test
181 181 changeset: 0:00a43fa82f62
182 182 user: test
183 183 date: Thu Jan 01 00:00:00 1970 +0000
184 184 summary: 0
185 185
186 186 changeset: 1:5460a410df01
187 187 user: test
188 188 date: Thu Jan 01 00:00:00 1970 +0000
189 189 summary: 1
190 190
191 191
192 192 limit to 2 changesets, test with -p --git
193 193
194 194 $ hg -R new incoming -l 2 -p --git test
195 195 comparing with test
196 196 changeset: 0:00a43fa82f62
197 197 user: test
198 198 date: Thu Jan 01 00:00:00 1970 +0000
199 199 summary: 0
200 200
201 201 diff --git a/foo b/foo
202 202 new file mode 100644
203 203 --- /dev/null
204 204 +++ b/foo
205 205 @@ -0,0 +1,1 @@
206 206 +0
207 207
208 208 changeset: 1:5460a410df01
209 209 user: test
210 210 date: Thu Jan 01 00:00:00 1970 +0000
211 211 summary: 1
212 212
213 213 diff --git a/foo b/foo
214 214 --- a/foo
215 215 +++ b/foo
216 216 @@ -1,1 +1,2 @@
217 217 0
218 218 +1
219 219
220 220
221 221 test with --bundle
222 222
223 223 $ hg -R new incoming --bundle test.hg http://localhost:$HGPORT/
224 224 comparing with http://localhost:$HGPORT/
225 225 changeset: 0:00a43fa82f62
226 226 user: test
227 227 date: Thu Jan 01 00:00:00 1970 +0000
228 228 summary: 0
229 229
230 230 changeset: 1:5460a410df01
231 231 user: test
232 232 date: Thu Jan 01 00:00:00 1970 +0000
233 233 summary: 1
234 234
235 235 changeset: 2:d9f42cd1a1ec
236 236 user: test
237 237 date: Thu Jan 01 00:00:00 1970 +0000
238 238 summary: 2
239 239
240 240 changeset: 3:376476025137
241 241 user: test
242 242 date: Thu Jan 01 00:00:00 1970 +0000
243 243 summary: 3
244 244
245 245 changeset: 4:70d7eb252d49
246 246 user: test
247 247 date: Thu Jan 01 00:00:00 1970 +0000
248 248 summary: 4
249 249
250 250 changeset: 5:ad284ee3b5ee
251 251 user: test
252 252 date: Thu Jan 01 00:00:00 1970 +0000
253 253 summary: 5
254 254
255 255 changeset: 6:e9229f2de384
256 256 user: test
257 257 date: Thu Jan 01 00:00:00 1970 +0000
258 258 summary: 6
259 259
260 260 changeset: 7:d152815bb8db
261 261 user: test
262 262 date: Thu Jan 01 00:00:00 1970 +0000
263 263 summary: 7
264 264
265 265 changeset: 8:e4feb4ac9035
266 266 tag: tip
267 267 user: test
268 268 date: Thu Jan 01 00:00:00 1970 +0000
269 269 summary: 8
270 270
271 271 $ hg -R new incoming --bundle test2.hg test
272 272 comparing with test
273 273 changeset: 0:00a43fa82f62
274 274 user: test
275 275 date: Thu Jan 01 00:00:00 1970 +0000
276 276 summary: 0
277 277
278 278 changeset: 1:5460a410df01
279 279 user: test
280 280 date: Thu Jan 01 00:00:00 1970 +0000
281 281 summary: 1
282 282
283 283 changeset: 2:d9f42cd1a1ec
284 284 user: test
285 285 date: Thu Jan 01 00:00:00 1970 +0000
286 286 summary: 2
287 287
288 288 changeset: 3:376476025137
289 289 user: test
290 290 date: Thu Jan 01 00:00:00 1970 +0000
291 291 summary: 3
292 292
293 293 changeset: 4:70d7eb252d49
294 294 user: test
295 295 date: Thu Jan 01 00:00:00 1970 +0000
296 296 summary: 4
297 297
298 298 changeset: 5:ad284ee3b5ee
299 299 user: test
300 300 date: Thu Jan 01 00:00:00 1970 +0000
301 301 summary: 5
302 302
303 303 changeset: 6:e9229f2de384
304 304 user: test
305 305 date: Thu Jan 01 00:00:00 1970 +0000
306 306 summary: 6
307 307
308 308 changeset: 7:d152815bb8db
309 309 user: test
310 310 date: Thu Jan 01 00:00:00 1970 +0000
311 311 summary: 7
312 312
313 313 changeset: 8:e4feb4ac9035
314 314 tag: tip
315 315 user: test
316 316 date: Thu Jan 01 00:00:00 1970 +0000
317 317 summary: 8
318 318
319 319
320 320
321 321 test the resulting bundles
322 322
323 323 $ hg init temp
324 324 $ hg init temp2
325 325 $ hg -R temp unbundle test.hg
326 326 adding changesets
327 327 adding manifests
328 328 adding file changes
329 329 added 9 changesets with 9 changes to 1 files
330 330 (run 'hg update' to get a working copy)
331 331 $ hg -R temp2 unbundle test2.hg
332 332 adding changesets
333 333 adding manifests
334 334 adding file changes
335 335 added 9 changesets with 9 changes to 1 files
336 336 (run 'hg update' to get a working copy)
337 337 $ hg -R temp tip
338 338 changeset: 8:e4feb4ac9035
339 339 tag: tip
340 340 user: test
341 341 date: Thu Jan 01 00:00:00 1970 +0000
342 342 summary: 8
343 343
344 344 $ hg -R temp2 tip
345 345 changeset: 8:e4feb4ac9035
346 346 tag: tip
347 347 user: test
348 348 date: Thu Jan 01 00:00:00 1970 +0000
349 349 summary: 8
350 350
351 351
352 352 $ rm -r temp temp2 new
353 353
354 354 test outgoing
355 355
356 356 $ hg clone test test-dev
357 357 updating to branch default
358 358 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 359 $ cd test-dev
360 360 $ for i in 9 10 11 12 13; do
361 361 > echo $i >> foo
362 362 > hg commit -A -m $i
363 363 > done
364 364 $ hg verify
365 365 checking changesets
366 366 checking manifests
367 367 crosschecking files in changesets and manifests
368 368 checking files
369 369 1 files, 14 changesets, 14 total revisions
370 370 $ cd ..
371 371 $ hg -R test-dev outgoing test
372 372 comparing with test
373 373 searching for changes
374 374 changeset: 9:d89d4abea5bc
375 375 user: test
376 376 date: Thu Jan 01 00:00:00 1970 +0000
377 377 summary: 9
378 378
379 379 changeset: 10:820095aa7158
380 380 user: test
381 381 date: Thu Jan 01 00:00:00 1970 +0000
382 382 summary: 10
383 383
384 384 changeset: 11:09ede2f3a638
385 385 user: test
386 386 date: Thu Jan 01 00:00:00 1970 +0000
387 387 summary: 11
388 388
389 389 changeset: 12:e576b1bed305
390 390 user: test
391 391 date: Thu Jan 01 00:00:00 1970 +0000
392 392 summary: 12
393 393
394 394 changeset: 13:96bbff09a7cc
395 395 tag: tip
396 396 user: test
397 397 date: Thu Jan 01 00:00:00 1970 +0000
398 398 summary: 13
399 399
400 400
401 401 limit to 3 changesets
402 402
403 403 $ hg -R test-dev outgoing -l 3 test
404 404 comparing with test
405 405 searching for changes
406 406 changeset: 9:d89d4abea5bc
407 407 user: test
408 408 date: Thu Jan 01 00:00:00 1970 +0000
409 409 summary: 9
410 410
411 411 changeset: 10:820095aa7158
412 412 user: test
413 413 date: Thu Jan 01 00:00:00 1970 +0000
414 414 summary: 10
415 415
416 416 changeset: 11:09ede2f3a638
417 417 user: test
418 418 date: Thu Jan 01 00:00:00 1970 +0000
419 419 summary: 11
420 420
421 421 $ hg -R test-dev outgoing http://localhost:$HGPORT/
422 422 comparing with http://localhost:$HGPORT/
423 423 searching for changes
424 424 changeset: 9:d89d4abea5bc
425 425 user: test
426 426 date: Thu Jan 01 00:00:00 1970 +0000
427 427 summary: 9
428 428
429 429 changeset: 10:820095aa7158
430 430 user: test
431 431 date: Thu Jan 01 00:00:00 1970 +0000
432 432 summary: 10
433 433
434 434 changeset: 11:09ede2f3a638
435 435 user: test
436 436 date: Thu Jan 01 00:00:00 1970 +0000
437 437 summary: 11
438 438
439 439 changeset: 12:e576b1bed305
440 440 user: test
441 441 date: Thu Jan 01 00:00:00 1970 +0000
442 442 summary: 12
443 443
444 444 changeset: 13:96bbff09a7cc
445 445 tag: tip
446 446 user: test
447 447 date: Thu Jan 01 00:00:00 1970 +0000
448 448 summary: 13
449 449
450 450 $ hg -R test-dev outgoing -r 11 http://localhost:$HGPORT/
451 451 comparing with http://localhost:$HGPORT/
452 452 searching for changes
453 453 changeset: 9:d89d4abea5bc
454 454 user: test
455 455 date: Thu Jan 01 00:00:00 1970 +0000
456 456 summary: 9
457 457
458 458 changeset: 10:820095aa7158
459 459 user: test
460 460 date: Thu Jan 01 00:00:00 1970 +0000
461 461 summary: 10
462 462
463 463 changeset: 11:09ede2f3a638
464 464 user: test
465 465 date: Thu Jan 01 00:00:00 1970 +0000
466 466 summary: 11
467 467
468
469 incoming from empty remote repository
470
471 $ hg init r1
472 $ hg init r2
473 $ echo a > r1/foo
474 $ hg -R r1 ci -Ama
475 adding foo
476 $ hg -R r1 incoming r2 --bundle x.hg
477 comparing with r2
478 searching for changes
479 no changes found
480 [1]
General Comments 0
You need to be logged in to leave comments. Login now