# HG changeset patch
# User Boris Feld <boris.f...@octobus.net>
# Date 1545041237 -3600
#      Mon Dec 17 11:07:17 2018 +0100
# Node ID 3294c80c1c71ab738a46bba671ee8e094a479fc6
# Parent  5e538853cc3267f20274e8eb032d40793f4a8b44
# EXP-Topic sparse-revlog-corner-cases
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 
3294c80c1c71
delta: have a native implementation of _findsnapshot

The function might traverse a lot of revision, a native implementation get
significantly faster.

example affected manifest write
before: 0.114989
after:  0.067141 (-42%)

diff --git a/mercurial/cext/revlog.c b/mercurial/cext/revlog.c
--- a/mercurial/cext/revlog.c
+++ b/mercurial/cext/revlog.c
@@ -1029,6 +1029,80 @@ static PyObject *index_issnapshot(indexO
        return PyBool_FromLong((long)issnap);
 }
 
+static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
+{
+
+       Py_ssize_t start_rev;
+       PyObject *cache;
+       Py_ssize_t base;
+       Py_ssize_t rev;
+       int issnap;
+       PyObject *key;
+       bool newallvalues;
+       PyObject *allvalues;
+       PyObject *value;
+       const Py_ssize_t length = index_length(self);
+       if (!PyArg_ParseTuple(args, "On", &cache, &start_rev)) {
+               return NULL;
+       }
+       if (!PyDict_Check(cache)) {
+               PyErr_SetString(PyExc_TypeError,
+                               "cache argument must be a dict");
+               return NULL;
+       }
+       for (rev = start_rev; rev < length; rev++) {
+               issnap = index_issnapshotrev(self, rev);
+               if (issnap < 0) {
+                       goto bail;
+               }
+               if (issnap == 0) {
+                       continue;
+               }
+               base = (Py_ssize_t)index_baserev(self, rev);
+               if (base == rev) {
+                       base = -1;
+               }
+               if (base == -2) {
+                       assert(PyErr_Occurred());
+                       goto bail;
+               }
+               key = PyInt_FromSsize_t(base);
+               newallvalues = false;
+               allvalues = PyDict_GetItem(cache, key);
+               if (allvalues == NULL && PyErr_Occurred()) {
+                       goto bail;
+               }
+               if (allvalues == NULL) {
+                       allvalues = PyList_New(0);
+                       newallvalues = true;
+                       if (PyDict_SetItem(cache, key, allvalues) < 0) {
+                               goto bail;
+                       }
+               }
+               value = PyInt_FromSsize_t(rev);
+               if (PyList_Append(allvalues, value)) {
+                       goto bail;
+               }
+               Py_XDECREF(key);
+               if (newallvalues) {
+                       Py_XDECREF(allvalues);
+               }
+               Py_XDECREF(value);
+               key = NULL;
+               allvalues = NULL;
+               value = NULL;
+       }
+       Py_INCREF(Py_None);
+       return Py_None;
+bail:
+       Py_XDECREF(key);
+       if (newallvalues) {
+               Py_XDECREF(allvalues);
+       }
+       Py_XDECREF(value);
+       return NULL;
+}
+
 static PyObject *index_deltachain(indexObject *self, PyObject *args)
 {
        int rev, generaldelta;
@@ -2643,6 +2717,8 @@ static PyMethodDef index_methods[] = {
      "get filtered head revisions"}, /* Can always do filtering */
     {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
      "True if the object is a snapshot"},
+    {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
+     "Gather snapshot data in a cache dict"},
     {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
      "determine revisions with deltas to reconstruct fulltext"},
     {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
diff --git a/mercurial/revlogutils/deltas.py b/mercurial/revlogutils/deltas.py
--- a/mercurial/revlogutils/deltas.py
+++ b/mercurial/revlogutils/deltas.py
@@ -30,6 +30,7 @@ from ..thirdparty import (
 from .. import (
     error,
     mdiff,
+    util,
 )
 
 # maximum <delta-chain-data>/<revision-text-length> ratio
@@ -676,11 +677,14 @@ def _candidategroups(revlog, textlen, p1
 
 def _findsnapshots(revlog, cache, start_rev):
     """find snapshot from start_rev to tip"""
-    deltaparent = revlog.deltaparent
-    issnapshot = revlog.issnapshot
-    for rev in revlog.revs(start_rev):
-        if issnapshot(rev):
-            cache[deltaparent(rev)].append(rev)
+    if util.safehasattr(revlog.index, 'findsnapshots'):
+        revlog.index.findsnapshots(cache, start_rev)
+    else:
+        deltaparent = revlog.deltaparent
+        issnapshot = revlog.issnapshot
+        for rev in revlog.revs(start_rev):
+            if issnapshot(rev):
+                cache[deltaparent(rev)].append(rev)
 
 def _refinedgroups(revlog, p1, p2, cachedelta):
     good = None
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to