[PATCH 1 of 3] revset: translate node directly with changelog in 'head'

Pierre-Yves David pierre-yves.david at ens-lyon.org
Thu Jun 18 12:05:20 CDT 2015


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1434509266 25200
#      Tue Jun 16 19:47:46 2015 -0700
# Node ID 36571390de341e29fe38d0fe53d30016834d3afe
# Parent  4e697f9a5c5c191db4651c09f26b1c1b5ac8b532
revset: translate node directly with changelog in 'head'

Using 'repo[X]' is much slower because it creates a 'changectx' object and goes
though multiple layers of code to do so. It is also error prone if there is
tags, bookmarks, branch or other names that could map to a node hash and take
precedence (user are wicked).

This provides a significant performance boost on repository with a lot of
heads.  Benchmark result for a repo with 1181 heads.

revset: head()
   plain         min           last          reverse
0) 0.014853      0.014371      0.014350      0.015161
1) 0.001402   9% 0.000975   6% 0.000874   6% 0.001415   9%

revset: head() - public()
   plain         min           last          reverse
0) 0.015121      0.014420      0.014560      0.015028
1) 0.001674  11% 0.001109   7% 0.000980   6% 0.001693  11%

revset: draft() and head()
   plain         min           last          reverse
0) 0.015976      0.014490      0.014214      0.015892
1) 0.002335  14% 0.001018   7% 0.000887   6% 0.002340  14%

The speed up is visible event when other more costly revset are in use

revset: head() and author("mpm")
   plain         min           last          reverse
0) 0.105419      0.090046      0.017169      0.108180
1) 0.090721  86% 0.077602  86% 0.003556  20% 0.093324  86%

diff --git a/contrib/all-revsets.txt b/contrib/all-revsets.txt
--- a/contrib/all-revsets.txt
+++ b/contrib/all-revsets.txt
@@ -116,5 +116,11 @@ roots((0:tip)::)
 (children(ancestor(tip~5, tip)) and ::(tip~5))::
 
 # those two `roots(...)` inputs are close to what phase movement use.
 roots((tip~100::) - (tip~100::tip))
 roots((0::) - (0::tip))
+
+# Testing the behavior of "head()" in various situations
+head()
+head() - public()
+draft() and head()
+head() and author("mpm")
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1105,12 +1105,13 @@ def head(repo, subset, x):
     Changeset is a named branch head.
     """
     # i18n: "head" is a keyword
     getargs(x, 0, 0, _("head takes no arguments"))
     hs = set()
+    cl = repo.changelog
     for b, ls in repo.branchmap().iteritems():
-        hs.update(repo[h].rev() for h in ls)
+        hs.update(cl.rev(h) for h in ls)
     # XXX using a set to feed the baseset is wrong. Sets are not ordered.
     # This does not break because of other fullreposet misbehavior.
     # XXX We should not be using '.filter' here, but combines subset with '&'
     # XXX We should combine with subset first: 'subset & baseset(...)'. This is
     # necessary to ensure we preserve the order in subset.


More information about the Mercurial-devel mailing list