[PATCH 5 of 6] dirs: use mutable integers internally
Bryan O'Sullivan
bos at serpentine.com
Mon Apr 1 15:49:18 CDT 2013
# HG changeset patch
# User Bryan O'Sullivan <bryano at fb.com>
# Date 1364849265 25200
# Mon Apr 01 13:47:45 2013 -0700
# Node ID 34666bf45a79c688f24fe15ce6a73894a6adfee6
# Parent 71ac3e4fd231239cf5c281cf49ff2fb78b883ce8
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
diff --git a/mercurial/dirs.c b/mercurial/dirs.c
--- a/mercurial/dirs.c
+++ b/mercurial/dirs.c
@@ -11,6 +11,13 @@
#include <Python.h>
#include "util.h"
+/*
+ * A few implementation notes:
+ *
+ * We modify Python integers for refcounting, but those integers are
+ * never visible to Python code.
+ */
+
typedef struct {
PyObject_HEAD
PyObject *dict;
@@ -32,12 +39,11 @@ static inline Py_ssize_t _finddir(PyObje
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);
@@ -45,25 +51,29 @@ static int _addpath(PyObject *dirs, PyOb
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;
}
@@ -71,12 +81,11 @@ bail:
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);
@@ -89,29 +98,16 @@ static int _delpath(PyObject *dirs, PyOb
"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;
}
More information about the Mercurial-devel
mailing list