_adjustlinkrev: reuse ancestors set during rename detection (
issue4514)
The new linkrev adjustement mechanism makes rename detection very slow, because
each file rewalks the ancestor dag. To mitigate the issue in Mercurial 3.3, we
introduce a simplistic way to share the ancestors computation for the linkrev
validation phase.
We can reuse the ancestors in that case because we do not care about
sub-branching in the ancestors graph.
The cached set will be use to check if the linkrev is valid in the search
context. This is the vast majority of the ancestors usage during copies search
since the uncached one will only be used when linkrev is invalid, which is
hopefully rare.
--- a/mercurial/context.py Fri Jan 30 14:39:03 2015 +0000
+++ b/mercurial/context.py Fri Jan 30 16:02:28 2015 +0000
@@ -766,10 +766,17 @@
# fetch the linkrev
fr = filelog.rev(fnode)
lkr = filelog.linkrev(fr)
+ # hack to reuse ancestor computation when searching for renames
+ memberanc = getattr(self, '_ancestrycontext', None)
+ iteranc = None
+ if memberanc is None:
+ memberanc = iteranc = cl.ancestors([srcrev], lkr,
+ inclusive=inclusive)
# check if this linkrev is an ancestor of srcrev
- anc = cl.ancestors([srcrev], lkr, inclusive=inclusive)
- if lkr not in anc:
- for a in anc:
+ if lkr not in memberanc:
+ if iteranc is None:
+ iteranc = cl.ancestors([srcrev], lkr, inclusive=inclusive)
+ for a in iteranc:
ac = cl.read(a) # get changeset data (we avoid object creation)
if path in ac[3]: # checking the 'files' field.
# The file has been touched, check if the content is
@@ -826,6 +833,8 @@
rev = self._adjustlinkrev(path, l, fnode, self.rev())
fctx = filectx(self._repo, path, fileid=fnode, filelog=l,
changeid=rev)
+ fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
+
else:
fctx = filectx(self._repo, path, fileid=fnode, filelog=l)
ret.append(fctx)
--- a/mercurial/copies.py Fri Jan 30 14:39:03 2015 +0000
+++ b/mercurial/copies.py Fri Jan 30 16:02:28 2015 +0000
@@ -170,8 +170,11 @@
missing = set(b.manifest().iterkeys())
missing.difference_update(a.manifest().iterkeys())
+ ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
for f in missing:
- ofctx = _tracefile(b[f], am, limit)
+ fctx = b[f]
+ fctx._ancestrycontext = ancestrycontext
+ ofctx = _tracefile(fctx, am, limit)
if ofctx:
cm[f] = ofctx.path()