comparison mercurial/manifest.py @ 40039:a0c18b271ea1

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
author spectral <spectral@google.com>
date Tue, 25 Sep 2018 19:25:41 -0700
parents 906c95073ff7
children 67b93cd847fb
comparison
equal deleted inserted replaced
40038:906c95073ff7 40039:a0c18b271ea1
699 699
700 def _subpath(self, path): 700 def _subpath(self, path):
701 return self._dir + path 701 return self._dir + path
702 702
703 def _loadalllazy(self): 703 def _loadalllazy(self):
704 for k, (path, node, readsubtree) in self._lazydirs.iteritems(): 704 selfdirs = self._dirs
705 self._dirs[k] = readsubtree(path, node) 705 for d, (path, node, readsubtree, docopy) in self._lazydirs.iteritems():
706 if docopy:
707 selfdirs[d] = readsubtree(path, node).copy()
708 else:
709 selfdirs[d] = readsubtree(path, node)
706 self._lazydirs = {} 710 self._lazydirs = {}
707 711
708 def _loadlazy(self, d): 712 def _loadlazy(self, d):
709 v = self._lazydirs.get(d) 713 v = self._lazydirs.get(d)
710 if v: 714 if v:
711 path, node, readsubtree = v 715 path, node, readsubtree, docopy = v
712 self._dirs[d] = readsubtree(path, node) 716 if docopy:
717 self._dirs[d] = readsubtree(path, node).copy()
718 else:
719 self._dirs[d] = readsubtree(path, node)
713 del self._lazydirs[d] 720 del self._lazydirs[d]
714 721
715 def _loadchildrensetlazy(self, visit): 722 def _loadchildrensetlazy(self, visit):
716 if not visit: 723 if not visit:
717 return None 724 return None
1168 selflazy = self._lazydirs 1175 selflazy = self._lazydirs
1169 subpath = self._subpath 1176 subpath = self._subpath
1170 for f, n, fl in _parse(text): 1177 for f, n, fl in _parse(text):
1171 if fl == 't': 1178 if fl == 't':
1172 f = f + '/' 1179 f = f + '/'
1173 selflazy[f] = (subpath(f), n, readsubtree) 1180 # False below means "doesn't need to be copied" and can use the
1181 # cached value from readsubtree directly.
1182 selflazy[f] = (subpath(f), n, readsubtree, False)
1174 elif '/' in f: 1183 elif '/' in f:
1175 # This is a flat manifest, so use __setitem__ and setflag rather 1184 # This is a flat manifest, so use __setitem__ and setflag rather
1176 # than assigning directly to _files and _flags, so we can 1185 # than assigning directly to _files and _flags, so we can
1177 # assign a path in a subdirectory, and to mark dirty (compared 1186 # assign a path in a subdirectory, and to mark dirty (compared
1178 # to nullid). 1187 # to nullid).
1195 """Get the full data of this directory as a bytestring. Make sure that 1204 """Get the full data of this directory as a bytestring. Make sure that
1196 any submanifests have been written first, so their nodeids are correct. 1205 any submanifests have been written first, so their nodeids are correct.
1197 """ 1206 """
1198 self._load() 1207 self._load()
1199 flags = self.flags 1208 flags = self.flags
1200 lazydirs = [(d[:-1], node, 't') for 1209 lazydirs = [(d[:-1], v[1], 't') for d, v in self._lazydirs.iteritems()]
1201 d, (path, node, readsubtree) in self._lazydirs.iteritems()]
1202 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs] 1210 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
1203 files = [(f, self._files[f], flags(f)) for f in self._files] 1211 files = [(f, self._files[f], flags(f)) for f in self._files]
1204 return _text(sorted(dirs + files + lazydirs)) 1212 return _text(sorted(dirs + files + lazydirs))
1205 1213
1206 def read(self, gettext, readsubtree): 1214 def read(self, gettext, readsubtree):