[PATCH 4 of 6 V2] rust: hooking into Python code

Georges Racinet gracinet at anybox.fr
Tue Oct 9 11:22:48 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 210cd79d35d50e989a7eabbcebb4addde9365f9e
# Parent  cf5c799e65a1225538fa1246887e2efd94c09acc
# EXP-Topic rustancestors-rfc
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 cf5c799e65a1 -r 210cd79d35d5 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 cf5c799e65a1 -r 210cd79d35d5 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 cf5c799e65a1 -r 210cd79d35d5 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