revlog: use the native implementation of issnapshot
authorBoris Feld <boris.feld@octobus.net>
Fri, 21 Dec 2018 05:27:38 +0100
changeset 41086 a28833d79aca
parent 41085 a6556b09bf83
child 41087 797a416a91bd
revlog: use the native implementation of issnapshot In some sparserevlog case where a lot of the history has to be searched for a snapshot, the cost of issnashot cost becomes significant. The computation done by the method is fairly low level, a native implementation provide a very significant speedup. example affected manifest write before: 0.490375s after: 0.114989s (-76%)
mercurial/cext/revlog.c
mercurial/revlog.py
--- a/mercurial/cext/revlog.c	Mon Dec 17 10:57:13 2018 +0100
+++ b/mercurial/cext/revlog.c	Fri Dec 21 05:27:38 2018 +0100
@@ -1029,6 +1029,27 @@
 	return rev == -1;
 }
 
+static PyObject *index_issnapshot(indexObject *self, PyObject *value)
+{
+	long rev;
+	int issnap;
+	Py_ssize_t length = index_length(self);
+
+	if (!pylong_to_long(value, &rev)) {
+		return NULL;
+	}
+	if (rev < -1 || rev >= length) {
+		PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
+		             rev);
+		return NULL;
+	};
+	issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
+	if (issnap < 0) {
+		return NULL;
+	};
+	return PyBool_FromLong((long)issnap);
+}
+
 static PyObject *index_deltachain(indexObject *self, PyObject *args)
 {
 	int rev, generaldelta;
@@ -2641,6 +2662,8 @@
      "get head revisions"}, /* Can do filtering since 3.2 */
     {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
      "get filtered head revisions"}, /* Can always do filtering */
+    {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
+     "True if the object is a snapshot"},
     {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
      "determine revisions with deltas to reconstruct fulltext"},
     {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
--- a/mercurial/revlog.py	Mon Dec 17 10:57:13 2018 +0100
+++ b/mercurial/revlog.py	Fri Dec 21 05:27:38 2018 +0100
@@ -1533,14 +1533,18 @@
     def issnapshot(self, rev):
         """tells whether rev is a snapshot
         """
+        if not self._sparserevlog:
+            return self.deltaparent(rev) == nullrev
+        elif util.safehasattr(self.index, 'issnapshot'):
+            # directly assign the method to cache the testing and access
+            self.issnapshot = self.index.issnapshot
+            return self.issnapshot(rev)
         if rev == nullrev:
             return True
         entry = self.index[rev]
         base = entry[3]
         if base == rev:
             return True
-        elif not self._sparserevlog:
-            return False
         if base == nullrev:
             return True
         p1 = entry[5]