changeset 13275:68da048b4c88

revlog: incrementally build node cache with linear searches This avoids needing to prime the cache for operations like verify which visit most or all of the index.
author Matt Mackall <mpm@selenic.com>
date Tue, 18 Jan 2011 15:55:46 -0600
parents 57d433f632b7
children ba6a63339f7c
files mercurial/revlog.py
diffstat 1 files changed, 27 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/revlog.py	Fri Jan 07 10:48:30 2011 +0100
+++ b/mercurial/revlog.py	Tue Jan 18 15:55:46 2011 -0600
@@ -176,10 +176,7 @@
     def parseindex(self, data, inline):
         # call the C implementation to parse the index data
         index, cache = parsers.parse_index2(data, inline)
-        nodemap = None
-        if not data:
-            nodemap = {nullid: nullrev}
-        return index, nodemap, cache
+        return index, None, cache
 
     def packentry(self, entry, node, version, rev):
         p = _pack(indexformatng, *entry)
@@ -228,6 +225,8 @@
         self._shallowroot = shallowroot
         self._parentdelta = 0
         self._pcache = {}
+        self._nodecache = {nullid: nullrev}
+        self._nodepos = None
 
         v = REVLOG_DEFAULT_VERSION
         if hasattr(opener, 'options') and 'defversion' in opener.options:
@@ -274,20 +273,10 @@
             raise RevlogError(_("index %s is corrupted") % (self.indexfile))
         self.index, nodemap, self._chunkcache = d
         if nodemap is not None:
-            self.nodemap = nodemap
-            self.rev = self._revmap
+            self.nodemap = self._nodecache = nodemap
         if not self._chunkcache:
             self._chunkclear()
 
-    @util.propertycache
-    def nodemap(self):
-        n = {nullid: nullrev}
-        i = self.index
-        for r in xrange(len(i) - 1):
-            n[i[r][7]] = r
-        self.rev = self._revmap
-        return n
-
     def tip(self):
         return self.node(len(self.index) - 2)
     def __len__(self):
@@ -295,20 +284,31 @@
     def __iter__(self):
         for i in xrange(len(self)):
             yield i
-    def _revmap(self, node):
-        try:
-            return self.nodemap[node]
-        except KeyError:
-            raise LookupError(node, self.indexfile, _('no node'))
+
+    @util.propertycache
+    def nodemap(self):
+        n = self.rev(self.node(0))
+        return self._nodecache
 
     def rev(self, node):
-        if node == nullid:
-            return nullrev
-        i = self.index
-        for r in xrange(len(i) - 2, -1, -1):
-            if i[r][7] == node:
-                return r
-        raise LookupError(node, self.indexfile, _('no node'))
+        try:
+            return self._nodecache[node]
+        except KeyError:
+            n = self._nodecache
+            if node in n:
+                return n[node]
+            i = self.index
+            p = self._nodepos
+            if p is None:
+                p = len(i) - 2
+            for r in xrange(p, -1, -1):
+                v = i[r][7]
+                n[v] = r
+                if v == node:
+                    self._nodepos = r - 1
+                    return r
+            raise LookupError(node, self.indexfile, _('no node'))
+
     def node(self, rev):
         return self.index[rev][7]
     def linkrev(self, rev):