--- a/hgext3rd/pullbundle.py Tue Sep 25 12:19:41 2018 +0200
+++ b/hgext3rd/pullbundle.py Tue Sep 25 12:20:26 2018 +0200
@@ -213,6 +213,16 @@
size = rangelength(rangeid)
slices.append((rangeid, nodes[idx:idx + size]))
idx += size
+ ### slow code block to validate ranges content
+ # rev = repo.changelog.nodemap.get
+ # for ri, ns in slices:
+ # a = set(rev(n) for n in ns)
+ # b = set(repo.stablerange.revsfromrange(repo, ri))
+ # l = repo.stablerange.rangelength(repo, ri)
+ # repo.ui.write('range-length: %d-%d %s %s\n' % (ri[0], ri[1], l, len(a)))
+ # if a != b:
+ # d = (ri[0], ri[1], b - a, a - b)
+ # repo.ui.write("mismatching content: %d-%d -%s +%s\n" % d)
return slices
def canonicalsubranges(repo, stablerange, rangeid):
@@ -246,38 +256,51 @@
# 2. optimise, bottom part
if skip != cut:
- tailranges = []
- tailsize = cut - skip
+ currentsize = tailsize = cut - skip
assert 0 < tailsize, tailsize
+
+ # we need to take several "standard cut" in the bottom part
+ #
+ # This is similar to what we will do for the top part, we reusing the
+ # existing structure is a bit more complex.
+ allcuts = list(reversed(standardcut(tailsize)))
prerange = (headrev, precut)
- size = stablerange.rangelength(repo, prerange)
- sub = stablerange.subranges(repo, prerange)[:-1]
- # This power of two check is too simplistic and misbehave when too many
- # merge are involved. because de merge, there can be "canonical" range
- # with various size.
- while not poweroftwo(tailsize):
- for prerange in reversed(sub):
- if tailsize <= 0:
- break
+ ### slow code block to check we operate on the right data
+ # rev = repo.changelog.nodemap.get
+ # allrevs = [rev(n) for n in nodes]
+ # allrevs.reverse()
+ # prerevs = repo.stablerange.revsfromrange(repo, prerange)
+ # assert allrevs == prerevs[(len(prerevs) - len(allrevs)):]
+ # end of check
+ sub = list(stablerange.subranges(repo, prerange)[:-1])
- assert stablerange.depthrev(repo, prerange[0]) != prerange[1], prerange
- tailrev, tailskip = prerange
- size = stablerange.rangelength(repo, (tailrev, tailskip))
- if tailsize < size:
- tailskip += size - tailsize
- size = tailsize
- tailranges.append((tailrev, tailskip))
- tailsize -= size
- else:
- # size of the last block
- tailsize = stablerange.rangelength(repo, tailranges[-1])
- if poweroftwo(tailsize):
- continue # exit the loop
- prerange = tailranges.pop()
- sub = stablerange.subranges(repo, prerange)
-
- tailranges.reverse()
- canonicals.extend(tailranges)
+ bottomranges = []
+ # XXX we might be able to reuse core stable-range logic instead of
+ # redoing this manually
+ currentrange = sub.pop()
+ currentsize = stablerange.rangelength(repo, currentrange)
+ currentcut = None
+ while allcuts or currentcut is not None:
+ # get the next cut if needed
+ if currentcut is None:
+ currentcut = allcuts.pop()
+ # deal attemp a cut
+ if currentsize == currentcut:
+ bottomranges.append(currentrange)
+ currentcut = None
+ elif currentsize < currentcut:
+ bottomranges.append(currentrange)
+ currentcut -= currentsize
+ else: # currentsize > currentcut
+ newskip = currentrange[1] + (currentsize - currentcut)
+ currentsub = stablerange._slicesrangeat(repo, currentrange, newskip)
+ bottomranges.append(currentsub.pop())
+ sub.extend(currentsub)
+ currentcut = None
+ currentrange = sub.pop()
+ currentsize = stablerange.rangelength(repo, currentrange)
+ bottomranges.reverse()
+ canonicals.extend(bottomranges)
# 3. take recursive subrange until we get to a power of two size?
current = (headrev, cut)
@@ -289,6 +312,22 @@
return canonicals
+def standardcut(size):
+ assert 0 < size
+ # 0. find the first power of 2 higher than this range depth
+ cut = 1
+ while cut <= size:
+ cut *= 2
+
+ allcuts = []
+ # 1. find all standard expected cut
+ while 1 < cut and size:
+ cut //= 2
+ if cut <= size:
+ allcuts.append(cut)
+ size -= cut
+ return allcuts
+
def poweroftwo(num):
return num and not num & (num - 1)