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%)
--- a/mercurial/cext/revlog.c Sun Dec 23 12:39:20 2018 +0900
+++ b/mercurial/cext/revlog.c Thu Dec 20 10:15:20 2018 +0100
@@ -1050,6 +1050,67 @@
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_RETURN_NONE;
+bail:
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ return NULL;
+}
+
static PyObject *index_deltachain(indexObject *self, PyObject *args)
{
int rev, generaldelta;
@@ -2664,6 +2725,8 @@
"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,
--- a/mercurial/revlogutils/deltas.py Sun Dec 23 12:39:20 2018 +0900
+++ b/mercurial/revlogutils/deltas.py Thu Dec 20 10:15:20 2018 +0100
@@ -30,6 +30,7 @@
from .. import (
error,
mdiff,
+ util,
)
# maximum <delta-chain-data>/<revision-text-length> ratio
@@ -688,11 +689,14 @@
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