# HG changeset patch # User Greg Ward # Date 1268187721 18000 # Node ID 64e286c22f29847dbd923799ad42dfa725c25a93 # Parent bc81f126139f45243b6df5affd6e4eaa360a15e9 shrink-revlog: add "reverse postorder" and "postorder reverse" toposorts. Based on a patch by Benoit Boissinot, adapted to the pluggable sort algorithm design. toposort_reversepostorder() is a very good performer; it's designed to recreate what the revlog would have looked like if Mercurial had parent deltas now. toposort_postorderreverse() is unstable and very inconsistent, but perhaps with some work it could be made better. diff -r bc81f126139f -r 64e286c22f29 contrib/shrink-revlog.py --- a/contrib/shrink-revlog.py Thu Feb 25 09:16:39 2010 -0500 +++ b/contrib/shrink-revlog.py Tue Mar 09 21:22:01 2010 -0500 @@ -81,6 +81,89 @@ ui.note(_('%d suboptimal nodes\n') % suboptimal) return result +def toposort_reversepostorder(ui, rl): + # postorder of the reverse directed graph + + # map rev to list of parent revs (p2 first) + parents = {} + heads = set() + ui.status(_('reading revs\n')) + try: + for rev in rl: + ui.progress(_('reading'), rev, total=len(rl)) + (p1, p2) = rl.parentrevs(rev) + if p1 == p2 == node.nullrev: + parents[rev] = () # root node + elif p1 == p2 or p2 == node.nullrev: + parents[rev] = (p1,) # normal node + else: + parents[rev] = (p2, p1) # merge node + + heads.add(rev) + + for p in parents[rev]: + heads.discard(p) + finally: + ui.progress(_('reading'), None, total=len(rl)) + + ui.status(_('sorting revs\n')) + result = [] + visit = list(heads) + visit.sort(reverse=True) + finished = set() + + while visit: + cur = visit[-1] + for p in parents[cur]: + if p not in finished: + visit.append(p) + break + else: + result.append(cur) + finished.add(cur) + visit.pop() + return result + +def toposort_postorderreverse(ui, rl): + # reverse-postorder of the reverse directed graph + + children = {} + roots = set() + ui.status(_('reading revs\n')) + try: + for rev in rl: + ui.progress(_('reading'), rev, total=len(rl)) + (p1, p2) = rl.parentrevs(rev) + if p1 == p2 == node.nullrev: + roots.add(rev) + + children[rev] = [] + + if p1 != node.nullrev: + children[p1].append(rev) + if p2 != node.nullrev: + children[p2].append(rev) + finally: + ui.progress(_('reading'), None, total=len(rl)) + + ui.status(_('sorting revs\n')) + result = [] + visit = list(roots) + visit.sort() + finished = set() + while visit: + cur = visit[-1] + for p in children[cur]: + if p not in finished: + visit.append(p) + break + else: + result.append(cur) + finished.add(cur) + visit.pop() + result.reverse() + return result + def writerevs(ui, r1, r2, order, tr): ui.status(_('writing revs\n'))