[PATCH 4 of 5 V3] rust: hooking into Python code

Georges Racinet gracinet at anybox.fr
Sat Oct 13 09:59:42 EDT 2018


# HG changeset patch
# User Georges Racinet <gracinet at anybox.fr>
# Date 1538060144 -7200
#      Thu Sep 27 16:55:44 2018 +0200
# Node ID 98f0f668f63b143eba344a74c8b22a0588f46935
# Parent  b1d2b4a4684a51ba9bfc3ea5bc6e177be65e4b69
# EXP-Topic rustancestors-contains
rust: hooking into Python code

We introduce a new class called 'rustlazyancestors'
in the ancestors module, which is used only if
parsers.rustlazyancestors does exist.

The implementation of __contains__ stays unchanged,
but is now backed by the Rust iterator. It would
probably be a good candidate for further development,
though, as it is mostly looping, and duplicates the
'seen' set.

The Rust code could be further optimized, however it already
gives rise to performance improvements:

median timing from hg perfancestors:
- on pypy:
    before: 0.113749s
    after:  0.018628s -84%
- on mozilla central:
    before: 0.329075s
    after:  0.083889s -75%
- on a private repository (about one million revisions):
    before: 1.982365s
    after:  0.329907s -83%
- on another private repository (about 400 000 revisions):
    before: 0.826686s
    after:  0.123760s -85%

median timing for hg perfbranchmap base
- on pypy:
    before:  1.808351s
    after:   0.480814s -73%
- on mozilla central:
    before: 18.493269s
    after:   1.305514s -93%
- on a private repository (about one million revisions):
    before:  9.153785s
    after:   3.662155s -60%
- on another private repository (about 400 000 revisions):
    before: 98.034737s
    after:  18.109361s -81%

diff -r b1d2b4a4684a -r 98f0f668f63b mercurial/ancestor.py
--- a/mercurial/ancestor.py	Thu Sep 27 16:56:15 2018 +0200
+++ b/mercurial/ancestor.py	Thu Sep 27 16:55:44 2018 +0200
@@ -11,9 +11,12 @@
 
 from .node import nullrev
 from . import (
+    policy,
     pycompat,
 )
 
+parsers = policy.importmod(r'parsers')
+
 def commonancestorsheads(pfunc, *nodes):
     """Returns a set with the heads of all common ancestors of all nodes,
     heads(::nodes[0] and ::nodes[1] and ...) .
@@ -379,3 +382,25 @@
             # free up memory.
             self._containsiter = None
             return False
+
+class rustlazyancestors(lazyancestors):
+
+    def __init__(self, index, revs, stoprev=0, inclusive=False):
+        self._index = index
+        self._stoprev = stoprev
+        self._inclusive = inclusive
+        # no need to prefilter out init revs that are smaller than stoprev,
+        # it's done by rustlazyancestors constructor.
+        # we need to convert to a list, because our ruslazyancestors
+        # constructor (from C code) doesn't understand anything else yet
+        self._initrevs = initrevs = list(revs)
+
+        self._containsseen = set()
+        self._containsiter = parsers.rustlazyancestors(
+            index, initrevs, stoprev, inclusive)
+
+    def __iter__(self):
+        return parsers.rustlazyancestors(self._index,
+                                         self._initrevs,
+                                         self._stoprev,
+                                         self._inclusive)
diff -r b1d2b4a4684a -r 98f0f668f63b mercurial/changelog.py
--- a/mercurial/changelog.py	Thu Sep 27 16:56:15 2018 +0200
+++ b/mercurial/changelog.py	Thu Sep 27 16:55:44 2018 +0200
@@ -20,14 +20,18 @@
 from . import (
     encoding,
     error,
+    policy,
     pycompat,
     revlog,
+    util,
 )
 from .utils import (
     dateutil,
     stringutil,
 )
 
+parsers = policy.importmod(r'parsers')
+
 _defaultextra = {'branch': 'default'}
 
 def _string_escape(text):
@@ -343,6 +347,14 @@
             if i not in self.filteredrevs:
                 yield i
 
+    def ancestors(self, revs, *args, **kwargs):
+        if util.safehasattr(parsers, 'rustlazyancestors') and self.filteredrevs:
+            missing = self.filteredrevs.difference(revs)
+            if missing:
+                # raise the lookup error
+                self.rev(min(missing))
+        return super(changelog, self).ancestors(revs, *args, **kwargs)
+
     def reachableroots(self, minroot, heads, roots, includepath=False):
         return self.index.reachableroots2(minroot, heads, roots, includepath)
 
diff -r b1d2b4a4684a -r 98f0f668f63b mercurial/revlog.py
--- a/mercurial/revlog.py	Thu Sep 27 16:56:15 2018 +0200
+++ b/mercurial/revlog.py	Thu Sep 27 16:55:44 2018 +0200
@@ -747,6 +747,10 @@
 
         See the documentation for ancestor.lazyancestors for more details."""
 
+        if util.safehasattr(parsers, 'rustlazyancestors'):
+            return ancestor.rustlazyancestors(
+                self.index, revs,
+                stoprev=stoprev, inclusive=inclusive)
         return ancestor.lazyancestors(self.parentrevs, revs, stoprev=stoprev,
                                       inclusive=inclusive)
 


More information about the Mercurial-devel mailing list