revlog: refactor delta chain computation into own function
authorGregory Szorc <gregory.szorc@gmail.com>
Sun, 20 Dec 2015 18:56:05 -0800
changeset 27468 93ac15f03331
parent 27467 fbe292b591ec
child 27469 8914296e74a2
revlog: refactor delta chain computation into own function This code is already written in multiple locations. While this code needs to be fast and extracting it to its own function adds overhead, code paths reading delta chains typically read, decompress, and do binary patching on revlog data from the delta chain. This other work (especially zlib decompression) almost certainly accounts for a lot more time than the overhead of introducing a Python function call. So I'm not worried about the performance impact of this change.
mercurial/revlog.py
--- a/mercurial/revlog.py	Sun Dec 20 17:57:44 2015 -0800
+++ b/mercurial/revlog.py	Sun Dec 20 18:56:05 2015 -0800
@@ -430,6 +430,41 @@
         chaininfocache[rev] = r
         return r
 
+    def _deltachain(self, rev, stoprev=None):
+        """Obtain the delta chain for a revision.
+
+        ``stoprev`` specifies a revision to stop at. If not specified, we
+        stop at the base of the chain.
+
+        Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
+        revs in ascending order and ``stopped`` is a bool indicating whether
+        ``stoprev`` was hit.
+        """
+        chain = []
+
+        # Alias to prevent attribute lookup in tight loop.
+        index = self.index
+        generaldelta = self._generaldelta
+
+        iterrev = rev
+        e = index[iterrev]
+        while iterrev != e[3] and iterrev != stoprev:
+            chain.append(iterrev)
+            if generaldelta:
+                iterrev = e[3]
+            else:
+                iterrev -= 1
+            e = index[iterrev]
+
+        if iterrev == stoprev:
+            stopped = True
+        else:
+            chain.append(iterrev)
+            stopped = False
+
+        chain.reverse()
+        return chain, stopped
+
     def flags(self, rev):
         return self.index[rev][0] & 0xFFFF
     def rawsize(self, rev):
@@ -1160,26 +1195,9 @@
             raise RevlogError(_('incompatible revision flag %x') %
                               (self.flags(rev) & ~REVIDX_KNOWN_FLAGS))
 
-        # build delta chain
-        chain = []
-        index = self.index # for performance
-        generaldelta = self._generaldelta
-        iterrev = rev
-        e = index[iterrev]
-        while iterrev != e[3] and iterrev != cachedrev:
-            chain.append(iterrev)
-            if generaldelta:
-                iterrev = e[3]
-            else:
-                iterrev -= 1
-            e = index[iterrev]
-
-        if iterrev == cachedrev:
-            # cache hit
+        chain, stopped = self._deltachain(rev, stoprev=cachedrev)
+        if stopped:
             text = self._cache[2]
-        else:
-            chain.append(iterrev)
-        chain.reverse()
 
         # drop cache to save memory
         self._cache = None