Mercurial > hg
changeset 18901:66d3aebe2d95
dirs: use mutable integers internally
These integers are not visible to Python code, so this is safe.
perfdirs results for a working dir with 170,000 files:
Python 638 msec
C 244
C+int 192
author | Bryan O'Sullivan <bryano@fb.com> |
---|---|
date | Wed, 10 Apr 2013 15:08:27 -0700 |
parents | 02ee846b246a |
children | 8c0a7eeda06d |
files | mercurial/dirs.c |
diffstat | 1 files changed, 20 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/dirs.c Wed Apr 10 15:08:27 2013 -0700 +++ b/mercurial/dirs.c Wed Apr 10 15:08:27 2013 -0700 @@ -14,6 +14,11 @@ /* * This is a multiset of directory names, built from the files that * appear in a dirstate or manifest. + * + * A few implementation notes: + * + * We modify Python integers for refcounting, but those integers are + * never visible to Python code. */ typedef struct { PyObject_HEAD @@ -36,12 +41,11 @@ static int _addpath(PyObject *dirs, PyObject *path) { Py_ssize_t pos = PyString_GET_SIZE(path); - PyObject *newval = NULL, *key = NULL; + PyObject *key = NULL; int ret = -1; while ((pos = _finddir(path, pos - 1)) != -1) { PyObject *val; - long v = 0; key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos); @@ -49,25 +53,29 @@ goto bail; val = PyDict_GetItem(dirs, key); - if (val != NULL) - v = PyInt_AS_LONG(val); + if (val != NULL) { + PyInt_AS_LONG(val) += 1; + Py_CLEAR(key); + continue; + } - newval = PyInt_FromLong(v + 1); + /* Force Python to not reuse a small shared int. */ + val = PyInt_FromLong(0x1eadbeef); - if (newval == NULL) + if (val == NULL) goto bail; - ret = PyDict_SetItem(dirs, key, newval); + PyInt_AS_LONG(val) = 1; + ret = PyDict_SetItem(dirs, key, val); + Py_DECREF(val); if (ret == -1) goto bail; Py_CLEAR(key); - Py_CLEAR(newval); } ret = 0; bail: Py_XDECREF(key); - Py_XDECREF(newval); return ret; } @@ -75,12 +83,11 @@ static int _delpath(PyObject *dirs, PyObject *path) { Py_ssize_t pos = PyString_GET_SIZE(path); - PyObject *newval = NULL, *key = NULL; + PyObject *key = NULL; int ret = -1; while ((pos = _finddir(path, pos - 1)) != -1) { PyObject *val; - long v; key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos); @@ -93,29 +100,16 @@ "expected a value, found none"); goto bail; } - v = PyInt_AS_LONG(val); - if (v <= 1) { - if (PyDict_DelItem(dirs, key) == -1) - goto bail; - continue; - } - newval = PyInt_FromLong(v - 1); - - if (newval == NULL) - goto bail; - - ret = PyDict_SetItem(dirs, key, newval); - if (ret == -1) + if (--PyInt_AS_LONG(val) <= 0 && + PyDict_DelItem(dirs, key) == -1) goto bail; Py_CLEAR(key); - Py_CLEAR(newval); } ret = 0; bail: Py_XDECREF(key); - Py_XDECREF(newval); return ret; }