Patchwork [3,of,5,V5] context: introduce an `isintroducedafter` method and use it in copies

mail settings
Submitter Boris Feld
Date Oct. 10, 2018, 8:41 a.m.
Message ID <501ef7b80a8bd6e2465c.1539160907@localhost.localdomain>
Download mbox | patch
Permalink /patch/35595/
State New
Headers show


Boris Feld - Oct. 10, 2018, 8:41 a.m.
# HG changeset patch
# User Boris Feld <>
# Date 1539125435 -7200
#      Wed Oct 10 00:50:35 2018 +0200
# Node ID 501ef7b80a8bd6e2465cc45b40beabfbf7b31bc8
# Parent  927d87bd28e0e7791b494a70701cb81a3ffad73d
# EXP-Topic copy-perf
# Available At
#              hg pull -r 501ef7b80a8b
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
unaware 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

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/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -762,6 +762,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 (self.linkrev() >= changelogrev
+                or self.introrev() >= changelogrev)
     def introrev(self):
         """return the rev of the changeset which introduced this file revision
diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -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):