obsolete: populate successors, precursors, children lazily
authorMartin von Zweigbergk <martinvonz@google.com>
Wed, 04 Feb 2015 22:25:35 -0800
changeset 24046 6e1d9f9932a9
parent 24045 43061f96e40e
child 24047 731fa8e3e580
obsolete: populate successors, precursors, children lazily The precursors and children dictionaries are not used by many commands. By making them lazily populated, 'hg log -r @~10::@ >/dev/null' is sped up from 0.564s to 0.440s on my hg.hg repo with 73k markers. Also make successors lazily populated, mostly for consistency with the others.
mercurial/obsolete.py
--- a/mercurial/obsolete.py	Wed Feb 04 22:40:48 2015 -0800
+++ b/mercurial/obsolete.py	Wed Feb 04 22:25:35 2015 -0800
@@ -75,6 +75,7 @@
 _pack = struct.pack
 _unpack = struct.unpack
 _calcsize = struct.calcsize
+propertycache = util.propertycache
 
 _SEEK_END = 2 # os.SEEK_END was introduced in Python 2.5
 
@@ -522,16 +523,13 @@
         # caches for various obsolescence related cache
         self.caches = {}
         self._all = []
-        self.precursors = {}
-        self.successors = {}
-        self.children = {}
         self.sopener = sopener
         data = sopener.tryread('obsstore')
         self._version = defaultformat
         self._readonly = readonly
         if data:
             self._version, markers = _readmarkers(data)
-            self._load(markers)
+            self._addmarkers(markers)
 
     def __iter__(self):
         return iter(self._all)
@@ -609,7 +607,7 @@
                 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
                 # call 'filecacheentry.refresh()'  here
                 f.close()
-            self._load(new)
+            self._addmarkers(new)
             # new marker *may* have changed several set. invalidate the cache.
             self.caches.clear()
         # records the number of new markers for the transaction hooks
@@ -624,12 +622,36 @@
         version, markers = _readmarkers(data)
         return self.add(transaction, markers)
 
-    def _load(self, markers):
+    @propertycache
+    def successors(self):
+        successors = {}
+        _addsuccessors(successors, self._all)
+        return successors
+
+    @propertycache
+    def precursors(self):
+        precursors = {}
+        _addprecursors(precursors, self._all)
+        return precursors
+
+    @propertycache
+    def children(self):
+        children = {}
+        _addchildren(children, self._all)
+        return children
+
+    def _cached(self, attr):
+        return attr in self.__dict__
+
+    def _addmarkers(self, markers):
         markers = list(markers) # to allow repeated iteration
         self._all.extend(markers)
-        _addsuccessors(self.successors, markers)
-        _addprecursors(self.precursors, markers)
-        _addchildren(self.children, markers)
+        if self._cached('successors'):
+            _addsuccessors(self.successors, markers)
+        if self._cached('precursors'):
+            _addprecursors(self.precursors, markers)
+        if self._cached('children'):
+            _addchildren(self.children, markers)
         _checkinvalidmarkers(markers)
 
     def relevantmarkers(self, nodes):