[PATCH 3 of 4] osutil: write a C implementation of statfiles for unix

Bryan O'Sullivan bos at serpentine.com
Fri Nov 30 16:20:05 CST 2012


# HG changeset patch
# User Bryan O'Sullivan <bryano at fb.com>
# Date 1354313914 28800
# Node ID 59ca9fefdb7d956cb76d04f3acc420289736957e
# Parent  47fa8e968f748579eda76bec9f897a31e54acacf
osutil: write a C implementation of statfiles for unix

This makes a big difference to performance.

In a clean working directory containing 170,000 files, performance of
"hg --time diff" improves from 2.38 seconds to 1.69.

diff --git a/mercurial/osutil.c b/mercurial/osutil.c
--- a/mercurial/osutil.c
+++ b/mercurial/osutil.c
@@ -389,6 +389,55 @@
 	return ret;
 }
 
+static PyObject *statfiles(PyObject *self, PyObject *args)
+{
+        PyObject *names, *stats;
+        Py_ssize_t i, count;
+
+        if (!PyArg_ParseTuple(args, "O:statfiles", &names))
+                return NULL;
+
+        count = PySequence_Length(names);
+        if (count == -1) {
+                PyErr_SetString(PyExc_TypeError, "not a sequence");
+                return NULL;
+        }
+
+        stats = PyList_New(count);
+        if (stats == NULL)
+                return NULL;
+
+        for (i = 0; i < count; i++) {
+                PyObject *stat;
+                struct stat st;
+                int ret, kind;
+                char *path;
+
+                path = PyString_AsString(PySequence_GetItem(names, i));
+                if (path == NULL) {
+                        PyErr_SetString(PyExc_TypeError, "not a string");
+                        goto bail;
+                }
+                ret = lstat(path, &st);
+                kind = st.st_mode & S_IFMT;
+                if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
+                        stat = makestat(&st);
+                        if (stat == NULL)
+                                goto bail;
+                        PyList_SET_ITEM(stats, i, stat);
+                } else {
+                        Py_INCREF(Py_None);
+                        PyList_SET_ITEM(stats, i, Py_None);
+                }
+        }
+
+        return stats;
+
+bail:
+        Py_DECREF(stats);
+        return NULL;
+}
+
 #endif /* ndef _WIN32 */
 
 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -553,6 +602,10 @@
 	{"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
 	 "Open a file with POSIX-like semantics.\n"
 "On error, this function may raise either a WindowsError or an IOError."},
+#else
+	{"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
+	 "stat a series of files or symlinks\n"
+"Returns None for non-existent entries and entries of other types.\n"},
 #endif
 #ifdef __APPLE__
 	{
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -64,7 +64,7 @@
 spawndetached = platform.spawndetached
 split = platform.split
 sshargs = platform.sshargs
-statfiles = platform.statfiles
+statfiles = getattr(osutil, 'statfiles', platform.statfiles)
 termwidth = platform.termwidth
 testpid = platform.testpid
 umask = platform.umask


More information about the Mercurial-devel mailing list