Patchwork [1,of,2,V6] delta: have a native implementation of _findsnapshot

login
register
mail settings
Submitter Boris Feld
Date Jan. 4, 2019, 11:23 a.m.
Message ID <ce19086bebe873ad5a1b.1546600980@localhost.localdomain>
Download mbox | patch
Permalink /patch/37451/
State Accepted
Headers show

Comments

Boris Feld - Jan. 4, 2019, 11:23 a.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1545297320 -3600
#      Thu Dec 20 10:15:20 2018 +0100
# Node ID ce19086bebe873ad5a1b62911721f2291fba766d
# Parent  9e593db5f1a1b08f812591439c831ace55bca321
# EXP-Topic sparse-revlog
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r ce19086bebe8
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%)
Yuya Nishihara - Jan. 5, 2019, 3:51 a.m.
On Fri, 04 Jan 2019 12:23:00 +0100, Boris Feld wrote:
> # HG changeset patch
> # User Boris Feld <boris.feld@octobus.net>
> # Date 1545297320 -3600
> #      Thu Dec 20 10:15:20 2018 +0100
> # Node ID ce19086bebe873ad5a1b62911721f2291fba766d
> # Parent  9e593db5f1a1b08f812591439c831ace55bca321
> # EXP-Topic sparse-revlog
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r ce19086bebe8
> delta: have a native implementation of _findsnapshot

Queued, thanks.

> +	Py_INCREF(Py_None);
> +	Py_RETURN_NONE;

Removed excessive Py_INCREF(Py_None).

Patch

diff --git a/mercurial/cext/revlog.c b/mercurial/cext/revlog.c
--- a/mercurial/cext/revlog.c
+++ b/mercurial/cext/revlog.c
@@ -1050,6 +1050,69 @@  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;
+	PyObject *key = NULL;
+	PyObject *value = NULL;
+	const Py_ssize_t length = index_length(self);
+	if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
+		return NULL;
+	}
+	for (rev = start_rev; rev < length; rev++) {
+		int issnap;
+		PyObject *allvalues = NULL;
+		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);
+		allvalues = PyDict_GetItem(cache, key);
+		if (allvalues == NULL && PyErr_Occurred()) {
+			goto bail;
+		}
+		if (allvalues == NULL) {
+			int r;
+			allvalues = PyList_New(0);
+			if (!allvalues) {
+				goto bail;
+			}
+			r = PyDict_SetItem(cache, key, allvalues);
+			Py_DECREF(allvalues);
+			if (r < 0) {
+				goto bail;
+			}
+		}
+		value = PyInt_FromSsize_t(rev);
+		if (PyList_Append(allvalues, value)) {
+			goto bail;
+		}
+		Py_CLEAR(key);
+		Py_CLEAR(value);
+	}
+	Py_INCREF(Py_None);
+	Py_RETURN_NONE;
+bail:
+	Py_XDECREF(key);
+	Py_XDECREF(value);
+	return NULL;
+}
+
 static PyObject *index_deltachain(indexObject *self, PyObject *args)
 {
 	int rev, generaldelta;
@@ -2664,6 +2727,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
@@ -688,11 +689,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