changeset 27468:93ac15f03331

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.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 20 Dec 2015 18:56:05 -0800
parents fbe292b591ec
children 8914296e74a2
files mercurial/revlog.py
diffstat 1 files changed, 37 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- 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