Mercurial > hg
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) |