treemanifests: store whether a lazydirs entry needs copied after materializing
authorspectral <spectral@google.com>
Tue, 25 Sep 2018 19:25:41 -0700
changeset 40039 a0c18b271ea1
parent 40038 906c95073ff7
child 40040 67b93cd847fb
treemanifests: store whether a lazydirs entry needs copied after materializing Due to the way that things like manifestlog.get caches its values, without making a copy (if necessary) after calling readsubtree(), we might end up adjusting the state of the same object on different contexts, breaking things like dirty state tracking (and probably other things). Differential Revision: https://phab.mercurial-scm.org/D4874
mercurial/manifest.py
--- a/mercurial/manifest.py	Tue Oct 02 18:55:07 2018 -0700
+++ b/mercurial/manifest.py	Tue Sep 25 19:25:41 2018 -0700
@@ -701,15 +701,22 @@
         return self._dir + path
 
     def _loadalllazy(self):
-        for k, (path, node, readsubtree) in self._lazydirs.iteritems():
-            self._dirs[k] = readsubtree(path, node)
+        selfdirs = self._dirs
+        for d, (path, node, readsubtree, docopy) in self._lazydirs.iteritems():
+            if docopy:
+                selfdirs[d] = readsubtree(path, node).copy()
+            else:
+                selfdirs[d] = readsubtree(path, node)
         self._lazydirs = {}
 
     def _loadlazy(self, d):
         v = self._lazydirs.get(d)
         if v:
-            path, node, readsubtree = v
-            self._dirs[d] = readsubtree(path, node)
+            path, node, readsubtree, docopy = v
+            if docopy:
+                self._dirs[d] = readsubtree(path, node).copy()
+            else:
+                self._dirs[d] = readsubtree(path, node)
             del self._lazydirs[d]
 
     def _loadchildrensetlazy(self, visit):
@@ -1170,7 +1177,9 @@
         for f, n, fl in _parse(text):
             if fl == 't':
                 f = f + '/'
-                selflazy[f] = (subpath(f), n, readsubtree)
+                # False below means "doesn't need to be copied" and can use the
+                # cached value from readsubtree directly.
+                selflazy[f] = (subpath(f), n, readsubtree, False)
             elif '/' in f:
                 # This is a flat manifest, so use __setitem__ and setflag rather
                 # than assigning directly to _files and _flags, so we can
@@ -1197,8 +1206,7 @@
         """
         self._load()
         flags = self.flags
-        lazydirs = [(d[:-1], node, 't') for
-                    d, (path, node, readsubtree) in self._lazydirs.iteritems()]
+        lazydirs = [(d[:-1], v[1], 't') for d, v in self._lazydirs.iteritems()]
         dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
         files = [(f, self._files[f], flags(f)) for f in self._files]
         return _text(sorted(dirs + files + lazydirs))