subranges: remove the recursivity of the call to isubranges(parentrange)
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Thu, 23 Mar 2017 10:44:12 +0100
changeset 2205 bd5e2496e5cd
parent 2204 61a8b51348a1
child 2206 84537469a094
subranges: remove the recursivity of the call to isubranges(parentrange) We add some logic to ensure we'll have hot cache for the parent ranges when that matters, the cache is filled from ancestors to descendant to ensure this. The range are still 'created from descendant to ancestors to fill the revsfromrange cache since it important.
hgext3rd/evolve/stablerange.py
--- a/hgext3rd/evolve/stablerange.py	Thu Mar 23 10:19:59 2017 +0100
+++ b/hgext3rd/evolve/stablerange.py	Thu Mar 23 10:44:12 2017 +0100
@@ -298,8 +298,45 @@
         if self.rangelength(repo, rangeid) == 1:
             return []
         slicepoint = self._slicepoint(repo, rangeid)
+
+        # make sure we have cache for all relevant parent first to prevent
+        # recursion (python is bad with recursion
+        stack = []
+        current = rangeid
+        while current is not None:
+            current = self._unpreparedparentrange(repo, current, slicepoint)
+            if current is not None:
+                stack.append(current)
+        while stack:
+            # these call will directly compute the subranges
+            self.subranges(repo, stack.pop())
         return self._slicesrangeat(repo, rangeid, slicepoint)
 
+    def _unpreparedparentrange(self, repo, rangeid, slicepoint):
+        """return parent range that it would be useful to prepare to slice
+        rangeid at slicepoint
+
+        This function also have the important task to update the revscache of
+        the parent revs if possible and needed"""
+        # is this is a merge, there is not need to prepare the parents.
+        p1, p2 = repo.changelog.parentrevs(rangeid[0])
+        if p2 != nodemod.nullrev:
+            return None
+        parentrange = (p1, rangeid[1])
+        # if we have an entry for the current range, lets update the cache
+        revscache = self._revsinrangecache
+        if rangeid in revscache and parentrange not in revscache:
+            parentrevs = self._revsinrangecache[rangeid][:-1]
+            self._revsinrangecache[parentrange] = parentrevs
+        # if we already have subrange for this range, no need to prepare it.
+        if self._subrangescache.get(parentrange) is not None:
+            return None
+        # if we reached the slicepoint, no need to go further
+        if self.depthrev(repo, parentrange[0]) == slicepoint:
+            return None
+        # look like we found a relevent parentrange with no cache yet
+        return parentrange
+
     def _slicepoint(self, repo, rangeid):
         rangedepth = self.depthrev(repo, rangeid[0])
         step = _hlp2(rangedepth)
@@ -334,12 +371,10 @@
             top = (rangeid[0], globalindex)
             return [parentrange, top]
         else:
-            # XXX recursive call, python have issue with them
-            # The best way to break it would be directly 'self.subranges'
-            # In that other method we could make sure subrangess for
-            # (p1(rev), idx) are available before slicing (rev, idx). But the
-            # heavy object approach makes it a bit inconvenient so that will
-            # wait for that heavy object to be gone.
+            # This will not initiate a recursion since we took appropriate
+            # precaution in the caller of this method to ensure it will be so.
+            # It the parent is a merge that will not be the case but computing
+            # subranges from a merge will not recurse.
             parentsubranges = self.subranges(repo, parentrange)
             slices = parentsubranges[:-1] # pop the top
             top = (rangeid[0], globalindex)