Mercurial > public > mercurial-scm > evolve
comparison hgext3rd/pullbundle.py @ 4138:cfdc6f55599b
pullbundle: improve slicing of the lower part of range
The previous method could get confuse by merge and overslice. The new method
is better at using sticking on power of two boundaries.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Tue, 25 Sep 2018 12:20:26 +0200 |
parents | be3a94d3105f |
children | 2bd652bece97 |
comparison
equal
deleted
inserted
replaced
4137:21a3c051ca6c | 4138:cfdc6f55599b |
---|---|
211 nodes.reverse() | 211 nodes.reverse() |
212 for rangeid in subranges: | 212 for rangeid in subranges: |
213 size = rangelength(rangeid) | 213 size = rangelength(rangeid) |
214 slices.append((rangeid, nodes[idx:idx + size])) | 214 slices.append((rangeid, nodes[idx:idx + size])) |
215 idx += size | 215 idx += size |
216 ### slow code block to validate ranges content | |
217 # rev = repo.changelog.nodemap.get | |
218 # for ri, ns in slices: | |
219 # a = set(rev(n) for n in ns) | |
220 # b = set(repo.stablerange.revsfromrange(repo, ri)) | |
221 # l = repo.stablerange.rangelength(repo, ri) | |
222 # repo.ui.write('range-length: %d-%d %s %s\n' % (ri[0], ri[1], l, len(a))) | |
223 # if a != b: | |
224 # d = (ri[0], ri[1], b - a, a - b) | |
225 # repo.ui.write("mismatching content: %d-%d -%s +%s\n" % d) | |
216 return slices | 226 return slices |
217 | 227 |
218 def canonicalsubranges(repo, stablerange, rangeid): | 228 def canonicalsubranges(repo, stablerange, rangeid): |
219 """slice a size of nodes into most reusable subranges | 229 """slice a size of nodes into most reusable subranges |
220 | 230 |
244 break | 254 break |
245 cursor //= 2 | 255 cursor //= 2 |
246 | 256 |
247 # 2. optimise, bottom part | 257 # 2. optimise, bottom part |
248 if skip != cut: | 258 if skip != cut: |
249 tailranges = [] | 259 currentsize = tailsize = cut - skip |
250 tailsize = cut - skip | |
251 assert 0 < tailsize, tailsize | 260 assert 0 < tailsize, tailsize |
261 | |
262 # we need to take several "standard cut" in the bottom part | |
263 # | |
264 # This is similar to what we will do for the top part, we reusing the | |
265 # existing structure is a bit more complex. | |
266 allcuts = list(reversed(standardcut(tailsize))) | |
252 prerange = (headrev, precut) | 267 prerange = (headrev, precut) |
253 size = stablerange.rangelength(repo, prerange) | 268 ### slow code block to check we operate on the right data |
254 sub = stablerange.subranges(repo, prerange)[:-1] | 269 # rev = repo.changelog.nodemap.get |
255 # This power of two check is too simplistic and misbehave when too many | 270 # allrevs = [rev(n) for n in nodes] |
256 # merge are involved. because de merge, there can be "canonical" range | 271 # allrevs.reverse() |
257 # with various size. | 272 # prerevs = repo.stablerange.revsfromrange(repo, prerange) |
258 while not poweroftwo(tailsize): | 273 # assert allrevs == prerevs[(len(prerevs) - len(allrevs)):] |
259 for prerange in reversed(sub): | 274 # end of check |
260 if tailsize <= 0: | 275 sub = list(stablerange.subranges(repo, prerange)[:-1]) |
261 break | 276 |
262 | 277 bottomranges = [] |
263 assert stablerange.depthrev(repo, prerange[0]) != prerange[1], prerange | 278 # XXX we might be able to reuse core stable-range logic instead of |
264 tailrev, tailskip = prerange | 279 # redoing this manually |
265 size = stablerange.rangelength(repo, (tailrev, tailskip)) | 280 currentrange = sub.pop() |
266 if tailsize < size: | 281 currentsize = stablerange.rangelength(repo, currentrange) |
267 tailskip += size - tailsize | 282 currentcut = None |
268 size = tailsize | 283 while allcuts or currentcut is not None: |
269 tailranges.append((tailrev, tailskip)) | 284 # get the next cut if needed |
270 tailsize -= size | 285 if currentcut is None: |
271 else: | 286 currentcut = allcuts.pop() |
272 # size of the last block | 287 # deal attemp a cut |
273 tailsize = stablerange.rangelength(repo, tailranges[-1]) | 288 if currentsize == currentcut: |
274 if poweroftwo(tailsize): | 289 bottomranges.append(currentrange) |
275 continue # exit the loop | 290 currentcut = None |
276 prerange = tailranges.pop() | 291 elif currentsize < currentcut: |
277 sub = stablerange.subranges(repo, prerange) | 292 bottomranges.append(currentrange) |
278 | 293 currentcut -= currentsize |
279 tailranges.reverse() | 294 else: # currentsize > currentcut |
280 canonicals.extend(tailranges) | 295 newskip = currentrange[1] + (currentsize - currentcut) |
296 currentsub = stablerange._slicesrangeat(repo, currentrange, newskip) | |
297 bottomranges.append(currentsub.pop()) | |
298 sub.extend(currentsub) | |
299 currentcut = None | |
300 currentrange = sub.pop() | |
301 currentsize = stablerange.rangelength(repo, currentrange) | |
302 bottomranges.reverse() | |
303 canonicals.extend(bottomranges) | |
281 | 304 |
282 # 3. take recursive subrange until we get to a power of two size? | 305 # 3. take recursive subrange until we get to a power of two size? |
283 current = (headrev, cut) | 306 current = (headrev, cut) |
284 while not poweroftwo(stablerange.rangelength(repo, current)): | 307 while not poweroftwo(stablerange.rangelength(repo, current)): |
285 sub = stablerange.subranges(repo, current) | 308 sub = stablerange.subranges(repo, current) |
286 canonicals.extend(sub[:-1]) | 309 canonicals.extend(sub[:-1]) |
287 current = sub[-1] | 310 current = sub[-1] |
288 canonicals.append(current) | 311 canonicals.append(current) |
289 | 312 |
290 return canonicals | 313 return canonicals |
314 | |
315 def standardcut(size): | |
316 assert 0 < size | |
317 # 0. find the first power of 2 higher than this range depth | |
318 cut = 1 | |
319 while cut <= size: | |
320 cut *= 2 | |
321 | |
322 allcuts = [] | |
323 # 1. find all standard expected cut | |
324 while 1 < cut and size: | |
325 cut //= 2 | |
326 if cut <= size: | |
327 allcuts.append(cut) | |
328 size -= cut | |
329 return allcuts | |
291 | 330 |
292 def poweroftwo(num): | 331 def poweroftwo(num): |
293 return num and not num & (num - 1) | 332 return num and not num & (num - 1) |
294 | 333 |
295 def outgoingfromnodes(repo, nodes): | 334 def outgoingfromnodes(repo, nodes): |