diff --git a/mercurial/manifest.py b/mercurial/manifest.py --- a/mercurial/manifest.py +++ b/mercurial/manifest.py @@ -685,6 +685,7 @@ self._copyfunc = _noop self._dirty = False self._dirs = {} + self._lazydirs = {} # Using _lazymanifest here is a little slower than plain old dicts self._files = {} self._flags = {} @@ -698,9 +699,20 @@ def _subpath(self, path): return self._dir + path + def _loadalllazy(self): + for k, (path, node, readsubtree) in self._lazydirs.iteritems(): + self._dirs[k] = readsubtree(path, node) + self._lazydirs = {} + + def _loadlazy(self, d): + path, node, readsubtree = self._lazydirs[d] + self._dirs[d] = readsubtree(path, node) + del self._lazydirs[d] + def __len__(self): self._load() size = len(self._files) + self._loadalllazy() for m in self._dirs.values(): size += m.__len__() return size @@ -713,6 +725,7 @@ def _isempty(self): self._load() # for consistency; already loaded by all callers + self._loadalllazy() return (not self._files and (not self._dirs or all(m._isempty() for m in self._dirs.values()))) @@ -740,6 +753,7 @@ def iterentries(self): self._load() + self._loadalllazy() for p, n in sorted(itertools.chain(self._dirs.items(), self._files.items())): if p in self._files: @@ -750,6 +764,7 @@ def items(self): self._load() + self._loadalllazy() for p, n in sorted(itertools.chain(self._dirs.items(), self._files.items())): if p in self._files: @@ -762,6 +777,7 @@ def iterkeys(self): self._load() + self._loadalllazy() for p in sorted(itertools.chain(self._dirs, self._files)): if p in self._files: yield self._subpath(p) @@ -781,8 +797,12 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) + if dir not in self._dirs: return False + return self._dirs[dir].__contains__(subpath) else: return f in self._files @@ -791,6 +811,9 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) + if dir not in self._dirs: return default return self._dirs[dir].get(subpath, default) @@ -801,6 +824,9 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) + return self._dirs[dir].__getitem__(subpath) else: return self._files[f] @@ -809,11 +835,14 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) + if dir not in self._dirs: return '' return self._dirs[dir].flags(subpath) else: - if f in self._dirs: + if f in self._lazydirs or f in self._dirs: return '' return self._flags.get(f, '') @@ -821,6 +850,9 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) + return self._dirs[dir].find(subpath) else: return self._files[f], self._flags.get(f, '') @@ -829,6 +861,9 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) + self._dirs[dir].__delitem__(subpath) # If the directory is now empty, remove it if self._dirs[dir]._isempty(): @@ -844,6 +879,8 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) if dir not in self._dirs: self._dirs[dir] = treemanifest(self._subpath(dir)) self._dirs[dir].__setitem__(subpath, n) @@ -864,6 +901,8 @@ self._load() dir, subpath = _splittopdir(f) if dir: + if dir in self._lazydirs: + self._loadlazy(dir) if dir not in self._dirs: self._dirs[dir] = treemanifest(self._subpath(dir)) self._dirs[dir].setflag(subpath, flags) @@ -878,6 +917,8 @@ if self._copyfunc is _noop: def _copyfunc(s): self._load() + for d in self._lazydirs: + s._lazydirs[d] = self._lazydirs[d] for d in self._dirs: s._dirs[d] = self._dirs[d].copy() s._files = dict.copy(self._files) @@ -903,6 +944,8 @@ return t1._load() t2._load() + t1._loadalllazy() + t2._loadalllazy() for d, m1 in t1._dirs.iteritems(): if d in t2._dirs: m2 = t2._dirs[d] @@ -928,10 +971,13 @@ self._load() topdir, subdir = _splittopdir(dir) if topdir: + if topdir in self._lazydirs: + self._loadlazy(topdir) if topdir in self._dirs: return self._dirs[topdir].hasdir(subdir) return False - return (dir + '/') in self._dirs + dirslash = dir + '/' + return dirslash in self._dirs or dirslash in self._lazydirs def walk(self, match): '''Generates matching file names. @@ -1005,6 +1051,8 @@ if fn in self._flags: ret._flags[fn] = self._flags[fn] + # OPT: use visitchildrenset to avoid loading everything + self._loadalllazy() for dir, subm in self._dirs.iteritems(): m = subm._matches(match) if not m._isempty(): @@ -1040,6 +1088,9 @@ return t1._load() t2._load() + # OPT: do we need to load everything? + t1._loadalllazy() + t2._loadalllazy() for d, m1 in t1._dirs.iteritems(): m2 = t2._dirs.get(d, emptytree) _diff(m1, m2) @@ -1099,9 +1150,11 @@ """ self._load() flags = self.flags + lazydirs = [(d[:-1], node, 't') for + d, (path, node, readsubtree) 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)) + return _text(sorted(dirs + files + lazydirs)) def read(self, gettext, readsubtree): def _load_for_read(s): @@ -1114,6 +1167,11 @@ m1._load() m2._load() emptytree = treemanifest() + # OPT: Do we really need to load everything? Presumably things in lazy + # aren't dirty and don't need to be written. + self._loadalllazy() + m1._loadalllazy() + m2._loadalllazy() for d, subm in self._dirs.iteritems(): subp1 = m1._dirs.get(d, emptytree)._node subp2 = m2._dirs.get(d, emptytree)._node @@ -1133,6 +1191,8 @@ yield self self._load() + # OPT: use visitchildrenset to avoid loading everything. + self._loadalllazy() for d, subm in self._dirs.iteritems(): for subtree in subm.walksubtrees(matcher=matcher): yield subtree