comparison mercurial/dirs.c @ 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
comparison
equal deleted inserted replaced
18900:02ee846b246a 18901:66d3aebe2d95
12 #include "util.h" 12 #include "util.h"
13 13
14 /* 14 /*
15 * This is a multiset of directory names, built from the files that 15 * This is a multiset of directory names, built from the files that
16 * appear in a dirstate or manifest. 16 * appear in a dirstate or manifest.
17 *
18 * A few implementation notes:
19 *
20 * We modify Python integers for refcounting, but those integers are
21 * never visible to Python code.
17 */ 22 */
18 typedef struct { 23 typedef struct {
19 PyObject_HEAD 24 PyObject_HEAD
20 PyObject *dict; 25 PyObject *dict;
21 } dirsObject; 26 } dirsObject;
34 } 39 }
35 40
36 static int _addpath(PyObject *dirs, PyObject *path) 41 static int _addpath(PyObject *dirs, PyObject *path)
37 { 42 {
38 Py_ssize_t pos = PyString_GET_SIZE(path); 43 Py_ssize_t pos = PyString_GET_SIZE(path);
39 PyObject *newval = NULL, *key = NULL; 44 PyObject *key = NULL;
40 int ret = -1; 45 int ret = -1;
41 46
42 while ((pos = _finddir(path, pos - 1)) != -1) { 47 while ((pos = _finddir(path, pos - 1)) != -1) {
43 PyObject *val; 48 PyObject *val;
44 long v = 0;
45 49
46 key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos); 50 key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);
47 51
48 if (key == NULL) 52 if (key == NULL)
49 goto bail; 53 goto bail;
50 54
51 val = PyDict_GetItem(dirs, key); 55 val = PyDict_GetItem(dirs, key);
52 if (val != NULL) 56 if (val != NULL) {
53 v = PyInt_AS_LONG(val); 57 PyInt_AS_LONG(val) += 1;
54 58 Py_CLEAR(key);
55 newval = PyInt_FromLong(v + 1); 59 continue;
56 60 }
57 if (newval == NULL) 61
58 goto bail; 62 /* Force Python to not reuse a small shared int. */
59 63 val = PyInt_FromLong(0x1eadbeef);
60 ret = PyDict_SetItem(dirs, key, newval); 64
65 if (val == NULL)
66 goto bail;
67
68 PyInt_AS_LONG(val) = 1;
69 ret = PyDict_SetItem(dirs, key, val);
70 Py_DECREF(val);
61 if (ret == -1) 71 if (ret == -1)
62 goto bail; 72 goto bail;
63 Py_CLEAR(key); 73 Py_CLEAR(key);
64 Py_CLEAR(newval);
65 } 74 }
66 ret = 0; 75 ret = 0;
67 76
68 bail: 77 bail:
69 Py_XDECREF(key); 78 Py_XDECREF(key);
70 Py_XDECREF(newval);
71 79
72 return ret; 80 return ret;
73 } 81 }
74 82
75 static int _delpath(PyObject *dirs, PyObject *path) 83 static int _delpath(PyObject *dirs, PyObject *path)
76 { 84 {
77 Py_ssize_t pos = PyString_GET_SIZE(path); 85 Py_ssize_t pos = PyString_GET_SIZE(path);
78 PyObject *newval = NULL, *key = NULL; 86 PyObject *key = NULL;
79 int ret = -1; 87 int ret = -1;
80 88
81 while ((pos = _finddir(path, pos - 1)) != -1) { 89 while ((pos = _finddir(path, pos - 1)) != -1) {
82 PyObject *val; 90 PyObject *val;
83 long v;
84 91
85 key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos); 92 key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);
86 93
87 if (key == NULL) 94 if (key == NULL)
88 goto bail; 95 goto bail;
91 if (val == NULL) { 98 if (val == NULL) {
92 PyErr_SetString(PyExc_ValueError, 99 PyErr_SetString(PyExc_ValueError,
93 "expected a value, found none"); 100 "expected a value, found none");
94 goto bail; 101 goto bail;
95 } 102 }
96 v = PyInt_AS_LONG(val); 103
97 104 if (--PyInt_AS_LONG(val) <= 0 &&
98 if (v <= 1) { 105 PyDict_DelItem(dirs, key) == -1)
99 if (PyDict_DelItem(dirs, key) == -1)
100 goto bail;
101 continue;
102 }
103 newval = PyInt_FromLong(v - 1);
104
105 if (newval == NULL)
106 goto bail;
107
108 ret = PyDict_SetItem(dirs, key, newval);
109 if (ret == -1)
110 goto bail; 106 goto bail;
111 Py_CLEAR(key); 107 Py_CLEAR(key);
112 Py_CLEAR(newval);
113 } 108 }
114 ret = 0; 109 ret = 0;
115 110
116 bail: 111 bail:
117 Py_XDECREF(key); 112 Py_XDECREF(key);
118 Py_XDECREF(newval);
119 113
120 return ret; 114 return ret;
121 } 115 }
122 116
123 static int dirs_fromdict(PyObject *dirs, PyObject *source, char skipchar) 117 static int dirs_fromdict(PyObject *dirs, PyObject *source, char skipchar)