diff -r 21a3c051ca6c -r cfdc6f55599b hgext3rd/pullbundle.py --- 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)