[PATCH 6 of 6 V5] reachableroots: default to the C implementation

Pierre-Yves David pierre-yves.david at ens-lyon.org
Fri Aug 7 16:06:55 CDT 2015


# HG changeset patch
# User Laurent Charignon <lcharignon at fb.com>
# Date 1438924280 25200
#      Thu Aug 06 22:11:20 2015 -0700
# Node ID b11862dc880057a56e5979456bb953d057d10c91
# Parent  62d61128bd7d35f668b3ff982567b2976601f616
reachableroots: default to the C implementation

This patch is part of a series of patches to speed up the computation of
revset.reachableroots by introducing a C implementation. The main motivation is to
speed up smartlog on big repositories. At the end of the series, on our big
repositories the computation of reachableroots is 10-50x faster and smartlog on is
2x-5x faster.

Before this patch, reachableroots was computed in pure Python by default. This
patch makes the C implementation the default and provides a speedup for
reachableroots.

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -76,24 +76,20 @@ def _revdescendants(repo, revs, followfi
                         yield i
                         break
 
     return generatorset(iterate(), iterasc=True)
 
-def reachableroots(repo, roots, heads, includepath=False):
+def reachablerootspure(repo, minroot, roots, heads, includepath):
     """return (heads(::<roots> and ::<heads>))
 
     If includepath is True, return (<roots>::<heads>)."""
     if not roots:
         return baseset()
     parentrevs = repo.changelog.parentrevs
     visit = list(heads)
     reachable = set()
     seen = {}
-    # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
-    # (and if it is not, it should.)
-    minroot = min(roots)
-    roots = set(roots)
     # prefetch all the things! (because python is slow)
     reached = reachable.add
     dovisit = visit.append
     nextvisit = visit.pop
     # open-code the post-order traversal due to the tiny size of
@@ -117,10 +113,26 @@ def reachableroots(repo, roots, heads, i
         for parent in seen[rev]:
             if parent in reachable:
                 reached(rev)
     return baseset(sorted(reachable))
 
+def reachableroots(repo, roots, heads, includepath=False):
+    """return (heads(::<roots> and ::<heads>))
+
+    If includepath is True, return (<roots>::<heads>)."""
+    if not roots:
+        return baseset()
+    # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
+    # (and if it is not, it should.)
+    minroot = min(roots)
+    roots = set(roots)
+    heads = list(heads)
+    try:
+        return repo.changelog.reachableroots(minroot, heads, roots, includepath)
+    except AttributeError:
+        return reachablerootspure(repo, minroot, roots, heads, includepath)
+
 elements = {
     # token-type: binding-strength, primary, prefix, infix, suffix
     "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
     "##": (20, None, None, ("_concat", 20), None),
     "~": (18, None, None, ("ancestor", 18), None),


More information about the Mercurial-devel mailing list