[PATCH 3 of 8 V3] context: introduce an `isintroducedafter` method and use it in copies

Boris Feld boris.feld at octobus.net
Wed Oct 3 15:10:46 EDT 2018


# HG changeset patch
# User Boris Feld <boris.feld at octobus.net>
# Date 1536252767 14400
#      Thu Sep 06 12:52:47 2018 -0400
# Node ID eb46ac11a9a81400e96ab3db00a38944a864100f
# Parent  355a69e274a2ec851c6d13cfbbac45f5e197294c
# EXP-Topic copy-perf
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r eb46ac11a9a8
context: introduce an `isintroducedafter` method and use it in copies

Right now, copy tracing make effort to not traverse the graph too much to save
performance. It uses a "limit" acting as a floor revision past which data are no
longer relevant to the current copy tracing.

However, to enforce this limit, it uses a call to `filectx.rev()`, that call can
trigger a graph traversal on its own. That extra graph traversal is oblivious of
the current limit and can become very expensive. That cost is increased by the
nature of work done in adjust link rev, we are not only walking down the graph,
we are also checking the affected file for each revision we walk through.
Something significantly more expensive than the walk itself.

To work around this we need to make the `filectx` operation aware of the current
limit. The first step is to introduce a dedicated method: `isintroducedafter`.
We'll then rework that method logic to stop traversal as soon as possible.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -765,6 +765,12 @@ class basefilectx(object):
             # result is crash somewhere else at to some point.
         return lkr
 
+    def isintroducedafter(self, changelogrev):
+        """True if a filectx have been introduced after a given floor revision
+        """
+        return (changelogrev <= self.linkrev()
+                or changelogrev <= self.introrev())
+
     def _lazyrevavailable(self):
         """return True if self.rev() is available without computation,
 
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -139,7 +139,7 @@ def _tracefile(fctx, am, limit=-1):
     for f in fctx.ancestors():
         if am.get(f.path(), None) == f.filenode():
             return f
-        if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
+        if limit >= 0 and not f.isintroducedafter(limit):
             return None
 
 def _dirstatecopies(d, match=None):


More information about the Mercurial-devel mailing list