[PATCH] rev: C implementation of delta chain resolution

Yuya Nishihara yuya at tcha.org
Tue Jun 27 14:24:43 UTC 2017


On Sun, 25 Jun 2017 12:42:53 -0700, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1498419694 25200
> #      Sun Jun 25 12:41:34 2017 -0700
> # Node ID 9e98095e4daca1f22c70f5374d1110c81be98cc4
> # Parent  8e3021fd1a44e48a4720bb6fa4538fba399ad213
> rev: C implementation of delta chain resolution

Generally looks good to me as this is a direct reimplementation of Python
version.

> --- a/mercurial/cext/revlog.c
> +++ b/mercurial/cext/revlog.c
> @@ -816,6 +816,139 @@ bail:
>  	return NULL;
>  }
>  
> +static inline int index_baserev(indexObject *self, int rev)
> +{
> +	const char *data;
> +
> +	if (rev >= self->length - 1) {
> +		PyObject *tuple = PyList_GET_ITEM(self->added,
> +			rev - self->length + 1);
> +		return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
> +	}
> +	else {
> +		data = index_deref(self, rev);
> +		if (data == NULL) {
> +			return -2;

Since index_deref() sets MemoryError by itself, callers of index_baserev()
should just return NULL on -2.

> +static PyObject *index_deltachain(indexObject *self, PyObject *args)
> +{
> +	int rev, generaldelta;
> +	PyObject *stoparg;
> +	int stoprev, iterrev, baserev = -1;
> +	int stopped;
> +	PyObject *chain = NULL, *value = NULL, *result = NULL;
> +	const Py_ssize_t length = index_length(self);
> +
> +	if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
> +		return NULL;
> +	}
> +
> +	if (PyInt_Check(stoparg)) {
> +		stoprev = (int)PyInt_AsLong(stoparg);
> +		if (stoprev == -1 && PyErr_Occurred()) {
> +			return NULL;
> +		}
> +	}
> +	else if (stoparg == Py_None) {
> +		stoprev = -2;
> +	}
> +	else {
> +		PyErr_SetString(PyExc_ValueError,
> +			"stoprev must be integer or None");
> +		return NULL;
> +	}
> +
> +	if (rev < 0 || rev >= length - 1) {
> +		PyErr_SetString(PyExc_ValueError, "revlog index out of range");
> +		return NULL;
> +	}
> +
> +	chain = PyList_New(0);
> +	if (chain == NULL) {
> +		return NULL;
> +	}
> +
> +	baserev = index_baserev(self, rev);
> +
> +	/* This should never happen. */
> +	if (baserev == -2) {
> +		PyErr_SetString(PyExc_IndexError, "unable to resolve data");
> +		goto bail;
> +	}
> +
> +	iterrev = rev;
> +
> +	while (iterrev != baserev && iterrev != stoprev) {
> +		value = PyInt_FromLong(iterrev);

Perhaps the scope of "value" could be narrowed as it isn't processed at the
global bail routine.

> +		if (value == NULL) {
> +			goto bail;
> +		}
> +		if (PyList_Append(chain, value)) {
> +			Py_DECREF(value);
> +			goto bail;
> +		}
> +		Py_DECREF(value);
> +
> +		if (generaldelta) {
> +			iterrev = baserev;
> +		}
> +		else {
> +			iterrev--;
> +		}
> +
> +		if (iterrev < 0) {
> +			break;
> +		}
> +
> +		if (iterrev >= length) {

Maybe 'iterrev >= length - 1'? index_baserev() seems not to handle the index
of the null entry, and the real null revision should be caught by the "break"
above.

> +			PyErr_SetString(PyExc_IndexError, "revision outside index");
> +			return NULL;
> +		}



More information about the Mercurial-devel mailing list