Re: [PATCH 2 of 3 gca-revset V2] revset: add optimization for heads(commonancestors())

2018-06-28 Thread Sean Farley

Yuya Nishihara  writes:

> On Tue, 26 Jun 2018 15:40:38 -0700, Sean Farley wrote:
>> # HG changeset patch
>> # User Sean Farley 
>> # Date 1530051981 25200
>> #  Tue Jun 26 15:26:21 2018 -0700
>> # Branch gca-revset
>> # Node ID 0bab83973dbaecf03167801ddc4550c4b8b581f1
>> # Parent  6034db436af9b15237bb87f82405eb039dfb
>> revset: add optimization for heads(commonancestors())
>
>> +from .ancestor import commonancestorsheads
>
> symbol import isn't allowed.

Argh, a bad habit I picked up from other python projects.

>> +# for internal use
>> +@predicate('_commonancestorheads(set)', safe=True)
>> +def _commonancestorheads(repo, subset, x):
>> +"""Returns all greatest common ancestors of the changesets.
>> +
>> +This is an internal method is for quickly calculating "heads(::x and 
>> ::y)"
>> +
>> +These greatest common ancestors are the same ones that the consesus bid
>> +merge will find.
>> +"""
>
> This has to be a comment. All docstrings are visible in the revset help.

Oops.

>> +h = heads(repo, subset, x)
>^^
>fullreposet(repo)
>
> heads may be out of the subset.

Yeah, agreed.


signature.asc
Description: PGP signature
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 3 gca-revset V2] revset: add optimization for heads(commonancestors())

2018-06-27 Thread Yuya Nishihara
On Tue, 26 Jun 2018 15:40:38 -0700, Sean Farley wrote:
> # HG changeset patch
> # User Sean Farley 
> # Date 1530051981 25200
> #  Tue Jun 26 15:26:21 2018 -0700
> # Branch gca-revset
> # Node ID 0bab83973dbaecf03167801ddc4550c4b8b581f1
> # Parent  6034db436af9b15237bb87f82405eb039dfb
> revset: add optimization for heads(commonancestors())

> +from .ancestor import commonancestorsheads

symbol import isn't allowed.

> +# for internal use
> +@predicate('_commonancestorheads(set)', safe=True)
> +def _commonancestorheads(repo, subset, x):
> +"""Returns all greatest common ancestors of the changesets.
> +
> +This is an internal method is for quickly calculating "heads(::x and 
> ::y)"
> +
> +These greatest common ancestors are the same ones that the consesus bid
> +merge will find.
> +"""

This has to be a comment. All docstrings are visible in the revset help.

> +h = heads(repo, subset, x)
   ^^
   fullreposet(repo)

heads may be out of the subset.

> +
> +try:
> +ancs = repo.changelog.index.commonancestorsheads(*list(h))
> +return subset & baseset(ancs)
> +except (AttributeError, OverflowError): # C implementation failed
> +return subset & commonancestorsheads(repo.changelog.parentrevs,
> + *list(h))
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 3 gca-revset V2] revset: add optimization for heads(commonancestors())

2018-06-26 Thread Sean Farley
# HG changeset patch
# User Sean Farley 
# Date 1530051981 25200
#  Tue Jun 26 15:26:21 2018 -0700
# Branch gca-revset
# Node ID 0bab83973dbaecf03167801ddc4550c4b8b581f1
# Parent  6034db436af9b15237bb87f82405eb039dfb
revset: add optimization for heads(commonancestors())

Previously, the only way to get these commits were (tested on
mozilla-central):

hg perfrevset 'heads(::a7cf55 and ::d8b15)'
! wall 4.988366 comb 4.96 user 4.78 sys 0.18 (best of 3)

After this patch:

(python)
hg perfrevset 'heads(commonancestors(a7cf55 + d8b15))'
! wall 0.002155 comb 0.00 user 0.00 sys 0.00 (best of 1107)

(C)
hg perfrevset 'heads(commonancestors(a7cf55 + d8b15))'
! wall 0.000568 comb 0.00 user 0.00 sys 0.00 (best of 4646)

diff --git a/mercurial/revset.py b/mercurial/revset.py
index 14e53e9..d5dc4eb 100644
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -7,10 +7,11 @@
 
 from __future__ import absolute_import
 
 import re
 
+from .ancestor import commonancestorsheads
 from .i18n import _
 from . import (
 dagop,
 destutil,
 encoding,
@@ -361,10 +362,30 @@ def ancestors(repo, subset, x):
 raise error.ParseError(_("negative depth"))
 stopdepth = n + 1
 return _ancestors(repo, subset, args['set'],
   startdepth=startdepth, stopdepth=stopdepth)
 
+# for internal use
+@predicate('_commonancestorheads(set)', safe=True)
+def _commonancestorheads(repo, subset, x):
+"""Returns all greatest common ancestors of the changesets.
+
+This is an internal method is for quickly calculating "heads(::x and ::y)"
+
+These greatest common ancestors are the same ones that the consesus bid
+merge will find.
+
+"""
+h = heads(repo, subset, x)
+
+try:
+ancs = repo.changelog.index.commonancestorsheads(*list(h))
+return subset & baseset(ancs)
+except (AttributeError, OverflowError): # C implementation failed
+return subset & commonancestorsheads(repo.changelog.parentrevs,
+ *list(h))
+
 @predicate('commonancestors(set)', safe=True)
 def commonancestors(repo, subset, x):
 """Returns all common ancestors of the set.
 
 This method is for calculating "::x and ::y" (i.e. all the ancestors that
diff --git a/mercurial/revsetlang.py b/mercurial/revsetlang.py
index 6331709..e559563 100644
--- a/mercurial/revsetlang.py
+++ b/mercurial/revsetlang.py
@@ -457,10 +457,16 @@ def _optimize(x):
 return w, (op, x[1], t)
 elif op == 'func':
 f = getsymbol(x[1])
 wa, ta = _optimize(x[2])
 w = getattr(symbols.get(f), '_weight', 1)
+m = _match('commonancestors(_)', ta)
+
+# Optimize heads(commonancestors(_)) because we have a fast version
+if f == 'heads' and m:
+return w + wa, _build('_commonancestorheads(_)', m[1])
+
 return w + wa, (op, x[1], ta)
 raise ValueError('invalid operator %r' % op)
 
 def optimize(tree):
 """Optimize evaluatable tree
diff --git a/tests/test-merge-criss-cross.t b/tests/test-merge-criss-cross.t
index 4901da2..40fe08e 100644
--- a/tests/test-merge-criss-cross.t
+++ b/tests/test-merge-criss-cross.t
@@ -484,10 +484,24 @@ http://stackoverflow.com/questions/93500
   a
   c
   b
   c
 
+Test the greatest common ancestor returning multiple changesets
+
+  $ hg log -r 'heads(commonancestors(head()))'
+  changeset:   1:0f6b37dbe527
+  user:test
+  date:Thu Jan 01 00:00:00 1970 +
+  summary: 1 first change f1
+
+  changeset:   2:d1d156401c1b
+  parent:  0:40494bf2444c
+  user:test
+  date:Thu Jan 01 00:00:00 1970 +
+  summary: 2 first change f2
+
 Verify that the old context ancestor works with / despite preferancestor:
 
   $ hg log -r 'ancestor(head())' --config merge.preferancestor=1 -T '{rev}\n'
   1
   $ hg log -r 'ancestor(head())' --config merge.preferancestor=2 -T '{rev}\n'
diff --git a/tests/test-revset2.t b/tests/test-revset2.t
index cfd0e08..d1db5d5 100644
--- a/tests/test-revset2.t
+++ b/tests/test-revset2.t
@@ -1832,5 +1832,23 @@ Test `draft() & ::x` optimization
   (symbol '_list')
   (string 'S1\x00D2\x00P5'))
 (keyvalue
   (symbol 'depth')
   (symbol '1')
+
+test commonancestors and its optimization
+
+  $ hg debugrevspec --verify -p analyzed -p optimized 
'heads(commonancestors(head()))'
+  * analyzed:
+  (func
+(symbol 'heads')
+(func
+  (symbol 'commonancestors')
+  (func
+(symbol 'head')
+None)))
+  * optimized:
+  (func
+(symbol '_commonancestorheads')
+(func
+  (symbol 'head')
+  None))
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel