osutil: write a C implementation of statfiles for unix
authorBryan O'Sullivan <bryano@fb.com>
Mon, 03 Dec 2012 12:40:24 -0800
changeset 18026 ddc0323db78b
parent 18021 9b05b31b413c
child 18027 4ca434500dbf
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.
mercurial/osutil.c
mercurial/util.py
--- a/mercurial/osutil.c	Fri Nov 30 17:40:11 2012 -0800
+++ b/mercurial/osutil.c	Mon Dec 03 12:40:24 2012 -0800
@@ -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__
 	{
--- a/mercurial/util.py	Fri Nov 30 17:40:11 2012 -0800
+++ b/mercurial/util.py	Mon Dec 03 12:40:24 2012 -0800
@@ -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