# HG changeset patch
# User spectral <spectral@google.com>
# Date 2018-09-26 02:25:41
# Node ID a0c18b271ea1ebc3c9ed91f95c2c9b3aa5f3d9f6
# Parent  906c95073ff76cf06bff6496212e1909c1d486f2

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

diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -701,15 +701,22 @@ class treemanifest(object):
         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 @@ class treemanifest(object):
         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 @@ class treemanifest(object):
         """
         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))