changeset 3267:f9206b009f48

stablesort: write a flat version of the algorithm This new version never needs to iterate over the full repository even when merge are encountered. Having the algorithm flat also prepare caching works since the iteration sequence can we expressed with a couple of flat loop.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Sun, 26 Nov 2017 10:34:46 -0500
parents bc173e7f3b6f
children 10badf5951e5
files hgext3rd/evolve/stablesort.py
diffstat 1 files changed, 64 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/hgext3rd/evolve/stablesort.py	Sat Nov 25 18:53:23 2017 -0500
+++ b/hgext3rd/evolve/stablesort.py	Sun Nov 26 10:34:46 2017 -0500
@@ -314,23 +314,77 @@
         return result
 
     def _revsfrom(self, repo, head):
-        parentsfunc = repo.changelog.parentrevs
+        tiebreaker = _mergepoint_tie_breaker(repo)
+        cl = repo.changelog
+        parentsfunc = cl.parentrevs
 
         def parents(rev):
-            return [p for p in parentsfunc(current) if p is not nodemod.nullrev]
+            return [p for p in parentsfunc(rev) if p is not nodemod.nullrev]
 
         current = head
-        ps = parents(current)
-        while len(ps) == 1:
+        previous_current = None
+
+        while current is not None:
+            assert current is not previous_current
             yield current
-            current = ps[0]
+            previous_current = current
+
+            ps = parents(current)
+            if not ps:
+                current = None # break
+            if len(ps) == 1:
+                current = ps[0]
+            elif len(ps) == 2:
+                lower_parent, higher_parent = sorted(ps, key=tiebreaker)
+
+                for rev in self._process_exclusive_side(lower_parent,
+                                                        higher_parent,
+                                                        cl.findmissingrevs,
+                                                        parents,
+                                                        tiebreaker):
+                    yield rev
+
+                current = lower_parent
+
+    def _process_exclusive_side(self, lower, higher, findmissingrevs, parents, tiebreaker):
+
+        exclusive = findmissingrevs(common=[lower],
+                                    heads=[higher])
+
+        stack = []
+        seen = set()
+        children = collections.defaultdict(set)
+        if not exclusive:
+            current = None
+        else:
+            current = higher
+            bound = set(exclusive)
+            for r in exclusive:
+                for p in parents(r):
+                    children[p].add(r)
+
+        previous_current = None
+        while current is not None:
+            assert current is not previous_current
+            yield current
+            seen.add(current)
+            previous_current = current
+
             ps = parents(current)
 
-        if not ps:
-            yield current
-        elif len(ps) == 2:
-            for rev in stablesort_mergepoint_head(repo, current)[::-1]:
-                yield rev
+            usable_parents = [p for p in ps
+                              if (p in bound and children[p].issubset(seen))]
+            if not usable_parents:
+                if stack:
+                    current = stack.pop()
+                else:
+                    current = None
+            elif len(usable_parents) == 1:
+                    current = usable_parents[0]
+            else:
+                lower_parent, higher_parent = sorted(usable_parents, key=tiebreaker)
+                stack.append(lower_parent)
+                current = higher_parent
 
 _methodmap = {
     'branchpoint': stablesort_branchpoint,