[PATCH] revset: introduce optional 'while' predicate for ancestors()
Mads Kiilerich
mads at kiilerich.com
Sat Oct 11 19:45:51 CDT 2014
On 10/11/2014 02:33 AM, Pierre-Yves David wrote:
> On 10/07/2014 05:22 PM, Mads Kiilerich wrote:
>> # HG changeset patch
>> # User Mads Kiilerich <madski at unity3d.com>
>> # Date 1412727753 -7200
>> # Wed Oct 08 02:22:33 2014 +0200
>> # Node ID 7c48c97a07b865c86a75562f94656a64a8506273
>> # Parent 564ae7d2ec9bee86b00a6ba817271ac0b19deca7
>> revset: introduce optional 'while' predicate for ancestors()
>>
>> When specifying a 'while' set, ancestors() will now only visit
>> parents that are
>> in that set. This makes it possible to prune while doing an ancestor
>> traversal
>> and reduce the number of membership tests. Such a pruning is very
>> convenient
>> when expensive checks are involved.
>
> Good feature, not really possible to achieve the same result easily
> (and definitely not with the same perf)
>
>>
>> The primary initial use case for this feature is that filtering on
>> branch name
>> is so expensive. Often it is just as relevant to prune everything not
>> on the
>> branch.
>>
>> Example:
>>
>> $ hg --time debugrevspec 'branch(.)' | wc -l
>> time: real 9.380 secs (user 9.200+0.000 sys 0.180+0.000)
>> 119
>>
>> $ hg --time debugrevspec 'ancestors(.)&branch(.)' | wc -l
>> time: real 10.070 secs (user 9.940+0.000 sys 0.110+0.000)
>> 119
>>
>> $ hg --time debugrevspec 'ancestors(., branch(.))' | wc -l
>> time: real 0.160 secs (user 0.140+0.000 sys 0.020+0.000)
>> 119
>
> Would be interested in output from the perf extension. Probably not
> worth adding an entry in the official benchmark. But I may be wrong.
What/how? The documentation of perf.py and its intended use is very
sparse. There is also no mentioning of how revsetbenchmarks.txt should
be used. The wiki gives no hits. I assume it is something that is
related to some facebook internal setup using internal repos.
>> diff --git a/mercurial/revset.py b/mercurial/revset.py
>> --- a/mercurial/revset.py
>> +++ b/mercurial/revset.py
>> @@ -17,7 +17,7 @@ import obsolete as obsmod
>> import pathutil
>> import repoview
>>
>> -def _revancestors(repo, revs, followfirst):
>> +def _revancestors(repo, revs, followfirst, while_=None):
>> """Like revlog.ancestors(), but supports followfirst."""
>> cut = followfirst and 1 or None
>> cl = repo.changelog
>> @@ -41,10 +41,11 @@ def _revancestors(repo, revs, followfirs
>> revsnode = revqueue.popleft()
>> heapq.heappush(h, -revsnode)
>> seen.add(current)
>> - yield current
>> - for parent in cl.parentrevs(current)[:cut]:
>> - if parent != node.nullrev:
>> - heapq.heappush(h, -parent)
>> + if while_ is None or current in while_:
>> + yield current
>> + for parent in cl.parentrevs(current)[:cut]:
>> + if parent != node.nullrev:
>> + heapq.heappush(h, -parent)
>>
>> return _generatorset(iterate(), iterasc=False)
>>
>> @@ -344,15 +345,22 @@ def ancestor(repo, subset, x):
>> return baseset([])
>>
>> def _ancestors(repo, subset, x, followfirst=False):
>> - args = getset(repo, spanset(repo), x)
>> + args = getargs(x, 0, 2, _('ancestors takes no, one or two
>> arguments'))
>> if not args:
>> return baseset([])
>> - s = _revancestors(repo, args, followfirst)
>> + heads = getset(repo, _spanset(repo), args[0])
>> + if not heads:
>> + return baseset([])
>> + while_ = None
>> + if len(args) > 1:
>> + while_ = getset(repo, _spanset(repo), args[1])
>
> _spanset(repo) is very very wrong. Should be spanset(repo) (or
> fullreposet(repo) as returned by the spanset call)
Why? The spanset docstring says the opposite. It suggests that all use
of spanset should replaced by either fullreposet or _spanset.
/Mads
More information about the Mercurial-devel
mailing list