##// END OF EJS Templates
pack_dirstate: in C version, for invalidation set dict to what we write to disk...
Siddharth Agarwal -
r21806:05bd2667 default
parent child Browse files
Show More
@@ -1,2080 +1,2087 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "util.h"
15 #include "util.h"
16
16
17 static char *versionerrortext = "Python minor version mismatch";
17 static char *versionerrortext = "Python minor version mismatch";
18
18
19 static int8_t hextable[256] = {
19 static int8_t hextable[256] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 };
36 };
37
37
38 static inline int hexdigit(const char *p, Py_ssize_t off)
38 static inline int hexdigit(const char *p, Py_ssize_t off)
39 {
39 {
40 int8_t val = hextable[(unsigned char)p[off]];
40 int8_t val = hextable[(unsigned char)p[off]];
41
41
42 if (val >= 0) {
42 if (val >= 0) {
43 return val;
43 return val;
44 }
44 }
45
45
46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
47 return 0;
47 return 0;
48 }
48 }
49
49
50 /*
50 /*
51 * Turn a hex-encoded string into binary.
51 * Turn a hex-encoded string into binary.
52 */
52 */
53 static PyObject *unhexlify(const char *str, int len)
53 static PyObject *unhexlify(const char *str, int len)
54 {
54 {
55 PyObject *ret;
55 PyObject *ret;
56 char *d;
56 char *d;
57 int i;
57 int i;
58
58
59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
60
60
61 if (!ret)
61 if (!ret)
62 return NULL;
62 return NULL;
63
63
64 d = PyBytes_AsString(ret);
64 d = PyBytes_AsString(ret);
65
65
66 for (i = 0; i < len;) {
66 for (i = 0; i < len;) {
67 int hi = hexdigit(str, i++);
67 int hi = hexdigit(str, i++);
68 int lo = hexdigit(str, i++);
68 int lo = hexdigit(str, i++);
69 *d++ = (hi << 4) | lo;
69 *d++ = (hi << 4) | lo;
70 }
70 }
71
71
72 return ret;
72 return ret;
73 }
73 }
74
74
75 /*
75 /*
76 * This code assumes that a manifest is stitched together with newline
76 * This code assumes that a manifest is stitched together with newline
77 * ('\n') characters.
77 * ('\n') characters.
78 */
78 */
79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
80 {
80 {
81 PyObject *mfdict, *fdict;
81 PyObject *mfdict, *fdict;
82 char *str, *start, *end;
82 char *str, *start, *end;
83 int len;
83 int len;
84
84
85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
86 &PyDict_Type, &mfdict,
86 &PyDict_Type, &mfdict,
87 &PyDict_Type, &fdict,
87 &PyDict_Type, &fdict,
88 &str, &len))
88 &str, &len))
89 goto quit;
89 goto quit;
90
90
91 start = str;
91 start = str;
92 end = str + len;
92 end = str + len;
93 while (start < end) {
93 while (start < end) {
94 PyObject *file = NULL, *node = NULL;
94 PyObject *file = NULL, *node = NULL;
95 PyObject *flags = NULL;
95 PyObject *flags = NULL;
96 char *zero = NULL, *newline = NULL;
96 char *zero = NULL, *newline = NULL;
97 ptrdiff_t nlen;
97 ptrdiff_t nlen;
98
98
99 zero = memchr(start, '\0', end - start);
99 zero = memchr(start, '\0', end - start);
100 if (!zero) {
100 if (!zero) {
101 PyErr_SetString(PyExc_ValueError,
101 PyErr_SetString(PyExc_ValueError,
102 "manifest entry has no separator");
102 "manifest entry has no separator");
103 goto quit;
103 goto quit;
104 }
104 }
105
105
106 newline = memchr(zero + 1, '\n', end - (zero + 1));
106 newline = memchr(zero + 1, '\n', end - (zero + 1));
107 if (!newline) {
107 if (!newline) {
108 PyErr_SetString(PyExc_ValueError,
108 PyErr_SetString(PyExc_ValueError,
109 "manifest contains trailing garbage");
109 "manifest contains trailing garbage");
110 goto quit;
110 goto quit;
111 }
111 }
112
112
113 file = PyBytes_FromStringAndSize(start, zero - start);
113 file = PyBytes_FromStringAndSize(start, zero - start);
114
114
115 if (!file)
115 if (!file)
116 goto bail;
116 goto bail;
117
117
118 nlen = newline - zero - 1;
118 nlen = newline - zero - 1;
119
119
120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
121 if (!node)
121 if (!node)
122 goto bail;
122 goto bail;
123
123
124 if (nlen > 40) {
124 if (nlen > 40) {
125 flags = PyBytes_FromStringAndSize(zero + 41,
125 flags = PyBytes_FromStringAndSize(zero + 41,
126 nlen - 40);
126 nlen - 40);
127 if (!flags)
127 if (!flags)
128 goto bail;
128 goto bail;
129
129
130 if (PyDict_SetItem(fdict, file, flags) == -1)
130 if (PyDict_SetItem(fdict, file, flags) == -1)
131 goto bail;
131 goto bail;
132 }
132 }
133
133
134 if (PyDict_SetItem(mfdict, file, node) == -1)
134 if (PyDict_SetItem(mfdict, file, node) == -1)
135 goto bail;
135 goto bail;
136
136
137 start = newline + 1;
137 start = newline + 1;
138
138
139 Py_XDECREF(flags);
139 Py_XDECREF(flags);
140 Py_XDECREF(node);
140 Py_XDECREF(node);
141 Py_XDECREF(file);
141 Py_XDECREF(file);
142 continue;
142 continue;
143 bail:
143 bail:
144 Py_XDECREF(flags);
144 Py_XDECREF(flags);
145 Py_XDECREF(node);
145 Py_XDECREF(node);
146 Py_XDECREF(file);
146 Py_XDECREF(file);
147 goto quit;
147 goto quit;
148 }
148 }
149
149
150 Py_INCREF(Py_None);
150 Py_INCREF(Py_None);
151 return Py_None;
151 return Py_None;
152 quit:
152 quit:
153 return NULL;
153 return NULL;
154 }
154 }
155
155
156 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
156 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
157 {
157 {
158 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
158 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
159 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
159 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
160 char state, *cur, *str, *cpos;
160 char state, *cur, *str, *cpos;
161 int mode, size, mtime;
161 int mode, size, mtime;
162 unsigned int flen;
162 unsigned int flen;
163 int len, pos = 40;
163 int len, pos = 40;
164
164
165 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
165 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
166 &PyDict_Type, &dmap,
166 &PyDict_Type, &dmap,
167 &PyDict_Type, &cmap,
167 &PyDict_Type, &cmap,
168 &str, &len))
168 &str, &len))
169 goto quit;
169 goto quit;
170
170
171 /* read parents */
171 /* read parents */
172 if (len < 40)
172 if (len < 40)
173 goto quit;
173 goto quit;
174
174
175 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
175 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
176 if (!parents)
176 if (!parents)
177 goto quit;
177 goto quit;
178
178
179 /* read filenames */
179 /* read filenames */
180 while (pos >= 40 && pos < len) {
180 while (pos >= 40 && pos < len) {
181 cur = str + pos;
181 cur = str + pos;
182 /* unpack header */
182 /* unpack header */
183 state = *cur;
183 state = *cur;
184 mode = getbe32(cur + 1);
184 mode = getbe32(cur + 1);
185 size = getbe32(cur + 5);
185 size = getbe32(cur + 5);
186 mtime = getbe32(cur + 9);
186 mtime = getbe32(cur + 9);
187 flen = getbe32(cur + 13);
187 flen = getbe32(cur + 13);
188 pos += 17;
188 pos += 17;
189 cur += 17;
189 cur += 17;
190 if (flen > len - pos) {
190 if (flen > len - pos) {
191 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
191 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
192 goto quit;
192 goto quit;
193 }
193 }
194
194
195 entry = Py_BuildValue("ciii", state, mode, size, mtime);
195 entry = Py_BuildValue("ciii", state, mode, size, mtime);
196 if (!entry)
196 if (!entry)
197 goto quit;
197 goto quit;
198 PyObject_GC_UnTrack(entry); /* don't waste time with this */
198 PyObject_GC_UnTrack(entry); /* don't waste time with this */
199
199
200 cpos = memchr(cur, 0, flen);
200 cpos = memchr(cur, 0, flen);
201 if (cpos) {
201 if (cpos) {
202 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
202 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
203 cname = PyBytes_FromStringAndSize(cpos + 1,
203 cname = PyBytes_FromStringAndSize(cpos + 1,
204 flen - (cpos - cur) - 1);
204 flen - (cpos - cur) - 1);
205 if (!fname || !cname ||
205 if (!fname || !cname ||
206 PyDict_SetItem(cmap, fname, cname) == -1 ||
206 PyDict_SetItem(cmap, fname, cname) == -1 ||
207 PyDict_SetItem(dmap, fname, entry) == -1)
207 PyDict_SetItem(dmap, fname, entry) == -1)
208 goto quit;
208 goto quit;
209 Py_DECREF(cname);
209 Py_DECREF(cname);
210 } else {
210 } else {
211 fname = PyBytes_FromStringAndSize(cur, flen);
211 fname = PyBytes_FromStringAndSize(cur, flen);
212 if (!fname ||
212 if (!fname ||
213 PyDict_SetItem(dmap, fname, entry) == -1)
213 PyDict_SetItem(dmap, fname, entry) == -1)
214 goto quit;
214 goto quit;
215 }
215 }
216 Py_DECREF(fname);
216 Py_DECREF(fname);
217 Py_DECREF(entry);
217 Py_DECREF(entry);
218 fname = cname = entry = NULL;
218 fname = cname = entry = NULL;
219 pos += flen;
219 pos += flen;
220 }
220 }
221
221
222 ret = parents;
222 ret = parents;
223 Py_INCREF(ret);
223 Py_INCREF(ret);
224 quit:
224 quit:
225 Py_XDECREF(fname);
225 Py_XDECREF(fname);
226 Py_XDECREF(cname);
226 Py_XDECREF(cname);
227 Py_XDECREF(entry);
227 Py_XDECREF(entry);
228 Py_XDECREF(parents);
228 Py_XDECREF(parents);
229 return ret;
229 return ret;
230 }
230 }
231
231
232 static inline int getintat(PyObject *tuple, int off, uint32_t *v)
232 static inline int getintat(PyObject *tuple, int off, uint32_t *v)
233 {
233 {
234 PyObject *o = PyTuple_GET_ITEM(tuple, off);
234 PyObject *o = PyTuple_GET_ITEM(tuple, off);
235 long val;
235 long val;
236
236
237 if (PyInt_Check(o))
237 if (PyInt_Check(o))
238 val = PyInt_AS_LONG(o);
238 val = PyInt_AS_LONG(o);
239 else if (PyLong_Check(o)) {
239 else if (PyLong_Check(o)) {
240 val = PyLong_AsLong(o);
240 val = PyLong_AsLong(o);
241 if (val == -1 && PyErr_Occurred())
241 if (val == -1 && PyErr_Occurred())
242 return -1;
242 return -1;
243 } else {
243 } else {
244 PyErr_SetString(PyExc_TypeError, "expected an int or long");
244 PyErr_SetString(PyExc_TypeError, "expected an int or long");
245 return -1;
245 return -1;
246 }
246 }
247 if (LONG_MAX > INT_MAX && (val > INT_MAX || val < INT_MIN)) {
247 if (LONG_MAX > INT_MAX && (val > INT_MAX || val < INT_MIN)) {
248 PyErr_SetString(PyExc_OverflowError,
248 PyErr_SetString(PyExc_OverflowError,
249 "Python value to large to convert to uint32_t");
249 "Python value to large to convert to uint32_t");
250 return -1;
250 return -1;
251 }
251 }
252 *v = (uint32_t)val;
252 *v = (uint32_t)val;
253 return 0;
253 return 0;
254 }
254 }
255
255
256 static PyObject *dirstate_unset;
256 static PyObject *dirstate_unset;
257
257
258 /*
258 /*
259 * Efficiently pack a dirstate object into its on-disk format.
259 * Efficiently pack a dirstate object into its on-disk format.
260 */
260 */
261 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
261 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
262 {
262 {
263 PyObject *packobj = NULL;
263 PyObject *packobj = NULL;
264 PyObject *map, *copymap, *pl;
264 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
265 Py_ssize_t nbytes, pos, l;
265 Py_ssize_t nbytes, pos, l;
266 PyObject *k, *v, *pn;
266 PyObject *k, *v, *pn;
267 char *p, *s;
267 char *p, *s;
268 double now;
268 double now;
269
269
270 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
270 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
271 &PyDict_Type, &map, &PyDict_Type, &copymap,
271 &PyDict_Type, &map, &PyDict_Type, &copymap,
272 &pl, &now))
272 &pl, &now))
273 return NULL;
273 return NULL;
274
274
275 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
275 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
276 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
276 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
277 return NULL;
277 return NULL;
278 }
278 }
279
279
280 /* Figure out how much we need to allocate. */
280 /* Figure out how much we need to allocate. */
281 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
281 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
282 PyObject *c;
282 PyObject *c;
283 if (!PyString_Check(k)) {
283 if (!PyString_Check(k)) {
284 PyErr_SetString(PyExc_TypeError, "expected string key");
284 PyErr_SetString(PyExc_TypeError, "expected string key");
285 goto bail;
285 goto bail;
286 }
286 }
287 nbytes += PyString_GET_SIZE(k) + 17;
287 nbytes += PyString_GET_SIZE(k) + 17;
288 c = PyDict_GetItem(copymap, k);
288 c = PyDict_GetItem(copymap, k);
289 if (c) {
289 if (c) {
290 if (!PyString_Check(c)) {
290 if (!PyString_Check(c)) {
291 PyErr_SetString(PyExc_TypeError,
291 PyErr_SetString(PyExc_TypeError,
292 "expected string key");
292 "expected string key");
293 goto bail;
293 goto bail;
294 }
294 }
295 nbytes += PyString_GET_SIZE(c) + 1;
295 nbytes += PyString_GET_SIZE(c) + 1;
296 }
296 }
297 }
297 }
298
298
299 packobj = PyString_FromStringAndSize(NULL, nbytes);
299 packobj = PyString_FromStringAndSize(NULL, nbytes);
300 if (packobj == NULL)
300 if (packobj == NULL)
301 goto bail;
301 goto bail;
302
302
303 p = PyString_AS_STRING(packobj);
303 p = PyString_AS_STRING(packobj);
304
304
305 pn = PySequence_ITEM(pl, 0);
305 pn = PySequence_ITEM(pl, 0);
306 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
306 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
307 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
307 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
308 goto bail;
308 goto bail;
309 }
309 }
310 memcpy(p, s, l);
310 memcpy(p, s, l);
311 p += 20;
311 p += 20;
312 pn = PySequence_ITEM(pl, 1);
312 pn = PySequence_ITEM(pl, 1);
313 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
313 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
314 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
314 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
315 goto bail;
315 goto bail;
316 }
316 }
317 memcpy(p, s, l);
317 memcpy(p, s, l);
318 p += 20;
318 p += 20;
319
319
320 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
320 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
321 uint32_t mode, size, mtime;
321 uint32_t mode, size, mtime;
322 Py_ssize_t len, l;
322 Py_ssize_t len, l;
323 PyObject *o;
323 PyObject *o;
324 char *s, *t;
324 char *s, *t;
325
325
326 if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) {
326 if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) {
327 PyErr_SetString(PyExc_TypeError, "expected a 4-tuple");
327 PyErr_SetString(PyExc_TypeError, "expected a 4-tuple");
328 goto bail;
328 goto bail;
329 }
329 }
330 o = PyTuple_GET_ITEM(v, 0);
330 o = PyTuple_GET_ITEM(v, 0);
331 if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) {
331 if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) {
332 PyErr_SetString(PyExc_TypeError, "expected one byte");
332 PyErr_SetString(PyExc_TypeError, "expected one byte");
333 goto bail;
333 goto bail;
334 }
334 }
335 *p++ = *s;
335 *p++ = *s;
336 if (getintat(v, 1, &mode) == -1)
336 if (getintat(v, 1, &mode) == -1)
337 goto bail;
337 goto bail;
338 if (getintat(v, 2, &size) == -1)
338 if (getintat(v, 2, &size) == -1)
339 goto bail;
339 goto bail;
340 if (getintat(v, 3, &mtime) == -1)
340 if (getintat(v, 3, &mtime) == -1)
341 goto bail;
341 goto bail;
342 if (*s == 'n' && mtime == (uint32_t)now) {
342 if (*s == 'n' && mtime == (uint32_t)now) {
343 /* See pure/parsers.py:pack_dirstate for why we do
343 /* See pure/parsers.py:pack_dirstate for why we do
344 * this. */
344 * this. */
345 if (PyDict_SetItem(map, k, dirstate_unset) == -1)
345 mtime = -1;
346 mtime_unset = Py_BuildValue(
347 "ciii", *s, mode, size, mtime);
348 if (!mtime_unset)
346 goto bail;
349 goto bail;
347 mtime = -1;
350 if (PyDict_SetItem(map, k, mtime_unset) == -1)
351 goto bail;
352 Py_DECREF(mtime_unset);
353 mtime_unset = NULL;
348 }
354 }
349 putbe32(mode, p);
355 putbe32(mode, p);
350 putbe32(size, p + 4);
356 putbe32(size, p + 4);
351 putbe32(mtime, p + 8);
357 putbe32(mtime, p + 8);
352 t = p + 12;
358 t = p + 12;
353 p += 16;
359 p += 16;
354 len = PyString_GET_SIZE(k);
360 len = PyString_GET_SIZE(k);
355 memcpy(p, PyString_AS_STRING(k), len);
361 memcpy(p, PyString_AS_STRING(k), len);
356 p += len;
362 p += len;
357 o = PyDict_GetItem(copymap, k);
363 o = PyDict_GetItem(copymap, k);
358 if (o) {
364 if (o) {
359 *p++ = '\0';
365 *p++ = '\0';
360 l = PyString_GET_SIZE(o);
366 l = PyString_GET_SIZE(o);
361 memcpy(p, PyString_AS_STRING(o), l);
367 memcpy(p, PyString_AS_STRING(o), l);
362 p += l;
368 p += l;
363 len += l + 1;
369 len += l + 1;
364 }
370 }
365 putbe32((uint32_t)len, t);
371 putbe32((uint32_t)len, t);
366 }
372 }
367
373
368 pos = p - PyString_AS_STRING(packobj);
374 pos = p - PyString_AS_STRING(packobj);
369 if (pos != nbytes) {
375 if (pos != nbytes) {
370 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
376 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
371 (long)pos, (long)nbytes);
377 (long)pos, (long)nbytes);
372 goto bail;
378 goto bail;
373 }
379 }
374
380
375 return packobj;
381 return packobj;
376 bail:
382 bail:
383 Py_XDECREF(mtime_unset);
377 Py_XDECREF(packobj);
384 Py_XDECREF(packobj);
378 return NULL;
385 return NULL;
379 }
386 }
380
387
381 /*
388 /*
382 * A base-16 trie for fast node->rev mapping.
389 * A base-16 trie for fast node->rev mapping.
383 *
390 *
384 * Positive value is index of the next node in the trie
391 * Positive value is index of the next node in the trie
385 * Negative value is a leaf: -(rev + 1)
392 * Negative value is a leaf: -(rev + 1)
386 * Zero is empty
393 * Zero is empty
387 */
394 */
388 typedef struct {
395 typedef struct {
389 int children[16];
396 int children[16];
390 } nodetree;
397 } nodetree;
391
398
392 /*
399 /*
393 * This class has two behaviours.
400 * This class has two behaviours.
394 *
401 *
395 * When used in a list-like way (with integer keys), we decode an
402 * When used in a list-like way (with integer keys), we decode an
396 * entry in a RevlogNG index file on demand. Our last entry is a
403 * entry in a RevlogNG index file on demand. Our last entry is a
397 * sentinel, always a nullid. We have limited support for
404 * sentinel, always a nullid. We have limited support for
398 * integer-keyed insert and delete, only at elements right before the
405 * integer-keyed insert and delete, only at elements right before the
399 * sentinel.
406 * sentinel.
400 *
407 *
401 * With string keys, we lazily perform a reverse mapping from node to
408 * With string keys, we lazily perform a reverse mapping from node to
402 * rev, using a base-16 trie.
409 * rev, using a base-16 trie.
403 */
410 */
404 typedef struct {
411 typedef struct {
405 PyObject_HEAD
412 PyObject_HEAD
406 /* Type-specific fields go here. */
413 /* Type-specific fields go here. */
407 PyObject *data; /* raw bytes of index */
414 PyObject *data; /* raw bytes of index */
408 PyObject **cache; /* cached tuples */
415 PyObject **cache; /* cached tuples */
409 const char **offsets; /* populated on demand */
416 const char **offsets; /* populated on demand */
410 Py_ssize_t raw_length; /* original number of elements */
417 Py_ssize_t raw_length; /* original number of elements */
411 Py_ssize_t length; /* current number of elements */
418 Py_ssize_t length; /* current number of elements */
412 PyObject *added; /* populated on demand */
419 PyObject *added; /* populated on demand */
413 PyObject *headrevs; /* cache, invalidated on changes */
420 PyObject *headrevs; /* cache, invalidated on changes */
414 nodetree *nt; /* base-16 trie */
421 nodetree *nt; /* base-16 trie */
415 int ntlength; /* # nodes in use */
422 int ntlength; /* # nodes in use */
416 int ntcapacity; /* # nodes allocated */
423 int ntcapacity; /* # nodes allocated */
417 int ntdepth; /* maximum depth of tree */
424 int ntdepth; /* maximum depth of tree */
418 int ntsplits; /* # splits performed */
425 int ntsplits; /* # splits performed */
419 int ntrev; /* last rev scanned */
426 int ntrev; /* last rev scanned */
420 int ntlookups; /* # lookups */
427 int ntlookups; /* # lookups */
421 int ntmisses; /* # lookups that miss the cache */
428 int ntmisses; /* # lookups that miss the cache */
422 int inlined;
429 int inlined;
423 } indexObject;
430 } indexObject;
424
431
425 static Py_ssize_t index_length(const indexObject *self)
432 static Py_ssize_t index_length(const indexObject *self)
426 {
433 {
427 if (self->added == NULL)
434 if (self->added == NULL)
428 return self->length;
435 return self->length;
429 return self->length + PyList_GET_SIZE(self->added);
436 return self->length + PyList_GET_SIZE(self->added);
430 }
437 }
431
438
432 static PyObject *nullentry;
439 static PyObject *nullentry;
433 static const char nullid[20];
440 static const char nullid[20];
434
441
435 static long inline_scan(indexObject *self, const char **offsets);
442 static long inline_scan(indexObject *self, const char **offsets);
436
443
437 #if LONG_MAX == 0x7fffffffL
444 #if LONG_MAX == 0x7fffffffL
438 static char *tuple_format = "Kiiiiiis#";
445 static char *tuple_format = "Kiiiiiis#";
439 #else
446 #else
440 static char *tuple_format = "kiiiiiis#";
447 static char *tuple_format = "kiiiiiis#";
441 #endif
448 #endif
442
449
443 /* A RevlogNG v1 index entry is 64 bytes long. */
450 /* A RevlogNG v1 index entry is 64 bytes long. */
444 static const long v1_hdrsize = 64;
451 static const long v1_hdrsize = 64;
445
452
446 /*
453 /*
447 * Return a pointer to the beginning of a RevlogNG record.
454 * Return a pointer to the beginning of a RevlogNG record.
448 */
455 */
449 static const char *index_deref(indexObject *self, Py_ssize_t pos)
456 static const char *index_deref(indexObject *self, Py_ssize_t pos)
450 {
457 {
451 if (self->inlined && pos > 0) {
458 if (self->inlined && pos > 0) {
452 if (self->offsets == NULL) {
459 if (self->offsets == NULL) {
453 self->offsets = malloc(self->raw_length *
460 self->offsets = malloc(self->raw_length *
454 sizeof(*self->offsets));
461 sizeof(*self->offsets));
455 if (self->offsets == NULL)
462 if (self->offsets == NULL)
456 return (const char *)PyErr_NoMemory();
463 return (const char *)PyErr_NoMemory();
457 inline_scan(self, self->offsets);
464 inline_scan(self, self->offsets);
458 }
465 }
459 return self->offsets[pos];
466 return self->offsets[pos];
460 }
467 }
461
468
462 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
469 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
463 }
470 }
464
471
465 /*
472 /*
466 * RevlogNG format (all in big endian, data may be inlined):
473 * RevlogNG format (all in big endian, data may be inlined):
467 * 6 bytes: offset
474 * 6 bytes: offset
468 * 2 bytes: flags
475 * 2 bytes: flags
469 * 4 bytes: compressed length
476 * 4 bytes: compressed length
470 * 4 bytes: uncompressed length
477 * 4 bytes: uncompressed length
471 * 4 bytes: base revision
478 * 4 bytes: base revision
472 * 4 bytes: link revision
479 * 4 bytes: link revision
473 * 4 bytes: parent 1 revision
480 * 4 bytes: parent 1 revision
474 * 4 bytes: parent 2 revision
481 * 4 bytes: parent 2 revision
475 * 32 bytes: nodeid (only 20 bytes used)
482 * 32 bytes: nodeid (only 20 bytes used)
476 */
483 */
477 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
484 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
478 {
485 {
479 uint64_t offset_flags;
486 uint64_t offset_flags;
480 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
487 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
481 const char *c_node_id;
488 const char *c_node_id;
482 const char *data;
489 const char *data;
483 Py_ssize_t length = index_length(self);
490 Py_ssize_t length = index_length(self);
484 PyObject *entry;
491 PyObject *entry;
485
492
486 if (pos < 0)
493 if (pos < 0)
487 pos += length;
494 pos += length;
488
495
489 if (pos < 0 || pos >= length) {
496 if (pos < 0 || pos >= length) {
490 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
497 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
491 return NULL;
498 return NULL;
492 }
499 }
493
500
494 if (pos == length - 1) {
501 if (pos == length - 1) {
495 Py_INCREF(nullentry);
502 Py_INCREF(nullentry);
496 return nullentry;
503 return nullentry;
497 }
504 }
498
505
499 if (pos >= self->length - 1) {
506 if (pos >= self->length - 1) {
500 PyObject *obj;
507 PyObject *obj;
501 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
508 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
502 Py_INCREF(obj);
509 Py_INCREF(obj);
503 return obj;
510 return obj;
504 }
511 }
505
512
506 if (self->cache) {
513 if (self->cache) {
507 if (self->cache[pos]) {
514 if (self->cache[pos]) {
508 Py_INCREF(self->cache[pos]);
515 Py_INCREF(self->cache[pos]);
509 return self->cache[pos];
516 return self->cache[pos];
510 }
517 }
511 } else {
518 } else {
512 self->cache = calloc(self->raw_length, sizeof(PyObject *));
519 self->cache = calloc(self->raw_length, sizeof(PyObject *));
513 if (self->cache == NULL)
520 if (self->cache == NULL)
514 return PyErr_NoMemory();
521 return PyErr_NoMemory();
515 }
522 }
516
523
517 data = index_deref(self, pos);
524 data = index_deref(self, pos);
518 if (data == NULL)
525 if (data == NULL)
519 return NULL;
526 return NULL;
520
527
521 offset_flags = getbe32(data + 4);
528 offset_flags = getbe32(data + 4);
522 if (pos == 0) /* mask out version number for the first entry */
529 if (pos == 0) /* mask out version number for the first entry */
523 offset_flags &= 0xFFFF;
530 offset_flags &= 0xFFFF;
524 else {
531 else {
525 uint32_t offset_high = getbe32(data);
532 uint32_t offset_high = getbe32(data);
526 offset_flags |= ((uint64_t)offset_high) << 32;
533 offset_flags |= ((uint64_t)offset_high) << 32;
527 }
534 }
528
535
529 comp_len = getbe32(data + 8);
536 comp_len = getbe32(data + 8);
530 uncomp_len = getbe32(data + 12);
537 uncomp_len = getbe32(data + 12);
531 base_rev = getbe32(data + 16);
538 base_rev = getbe32(data + 16);
532 link_rev = getbe32(data + 20);
539 link_rev = getbe32(data + 20);
533 parent_1 = getbe32(data + 24);
540 parent_1 = getbe32(data + 24);
534 parent_2 = getbe32(data + 28);
541 parent_2 = getbe32(data + 28);
535 c_node_id = data + 32;
542 c_node_id = data + 32;
536
543
537 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
544 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
538 uncomp_len, base_rev, link_rev,
545 uncomp_len, base_rev, link_rev,
539 parent_1, parent_2, c_node_id, 20);
546 parent_1, parent_2, c_node_id, 20);
540
547
541 if (entry) {
548 if (entry) {
542 PyObject_GC_UnTrack(entry);
549 PyObject_GC_UnTrack(entry);
543 Py_INCREF(entry);
550 Py_INCREF(entry);
544 }
551 }
545
552
546 self->cache[pos] = entry;
553 self->cache[pos] = entry;
547
554
548 return entry;
555 return entry;
549 }
556 }
550
557
551 /*
558 /*
552 * Return the 20-byte SHA of the node corresponding to the given rev.
559 * Return the 20-byte SHA of the node corresponding to the given rev.
553 */
560 */
554 static const char *index_node(indexObject *self, Py_ssize_t pos)
561 static const char *index_node(indexObject *self, Py_ssize_t pos)
555 {
562 {
556 Py_ssize_t length = index_length(self);
563 Py_ssize_t length = index_length(self);
557 const char *data;
564 const char *data;
558
565
559 if (pos == length - 1 || pos == INT_MAX)
566 if (pos == length - 1 || pos == INT_MAX)
560 return nullid;
567 return nullid;
561
568
562 if (pos >= length)
569 if (pos >= length)
563 return NULL;
570 return NULL;
564
571
565 if (pos >= self->length - 1) {
572 if (pos >= self->length - 1) {
566 PyObject *tuple, *str;
573 PyObject *tuple, *str;
567 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
574 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
568 str = PyTuple_GetItem(tuple, 7);
575 str = PyTuple_GetItem(tuple, 7);
569 return str ? PyString_AS_STRING(str) : NULL;
576 return str ? PyString_AS_STRING(str) : NULL;
570 }
577 }
571
578
572 data = index_deref(self, pos);
579 data = index_deref(self, pos);
573 return data ? data + 32 : NULL;
580 return data ? data + 32 : NULL;
574 }
581 }
575
582
576 static int nt_insert(indexObject *self, const char *node, int rev);
583 static int nt_insert(indexObject *self, const char *node, int rev);
577
584
578 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
585 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
579 {
586 {
580 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
587 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
581 return -1;
588 return -1;
582 if (*nodelen == 20)
589 if (*nodelen == 20)
583 return 0;
590 return 0;
584 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
591 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
585 return -1;
592 return -1;
586 }
593 }
587
594
588 static PyObject *index_insert(indexObject *self, PyObject *args)
595 static PyObject *index_insert(indexObject *self, PyObject *args)
589 {
596 {
590 PyObject *obj;
597 PyObject *obj;
591 char *node;
598 char *node;
592 long offset;
599 long offset;
593 Py_ssize_t len, nodelen;
600 Py_ssize_t len, nodelen;
594
601
595 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
602 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
596 return NULL;
603 return NULL;
597
604
598 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
605 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
599 PyErr_SetString(PyExc_TypeError, "8-tuple required");
606 PyErr_SetString(PyExc_TypeError, "8-tuple required");
600 return NULL;
607 return NULL;
601 }
608 }
602
609
603 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
610 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
604 return NULL;
611 return NULL;
605
612
606 len = index_length(self);
613 len = index_length(self);
607
614
608 if (offset < 0)
615 if (offset < 0)
609 offset += len;
616 offset += len;
610
617
611 if (offset != len - 1) {
618 if (offset != len - 1) {
612 PyErr_SetString(PyExc_IndexError,
619 PyErr_SetString(PyExc_IndexError,
613 "insert only supported at index -1");
620 "insert only supported at index -1");
614 return NULL;
621 return NULL;
615 }
622 }
616
623
617 if (offset > INT_MAX) {
624 if (offset > INT_MAX) {
618 PyErr_SetString(PyExc_ValueError,
625 PyErr_SetString(PyExc_ValueError,
619 "currently only 2**31 revs supported");
626 "currently only 2**31 revs supported");
620 return NULL;
627 return NULL;
621 }
628 }
622
629
623 if (self->added == NULL) {
630 if (self->added == NULL) {
624 self->added = PyList_New(0);
631 self->added = PyList_New(0);
625 if (self->added == NULL)
632 if (self->added == NULL)
626 return NULL;
633 return NULL;
627 }
634 }
628
635
629 if (PyList_Append(self->added, obj) == -1)
636 if (PyList_Append(self->added, obj) == -1)
630 return NULL;
637 return NULL;
631
638
632 if (self->nt)
639 if (self->nt)
633 nt_insert(self, node, (int)offset);
640 nt_insert(self, node, (int)offset);
634
641
635 Py_CLEAR(self->headrevs);
642 Py_CLEAR(self->headrevs);
636 Py_RETURN_NONE;
643 Py_RETURN_NONE;
637 }
644 }
638
645
639 static void _index_clearcaches(indexObject *self)
646 static void _index_clearcaches(indexObject *self)
640 {
647 {
641 if (self->cache) {
648 if (self->cache) {
642 Py_ssize_t i;
649 Py_ssize_t i;
643
650
644 for (i = 0; i < self->raw_length; i++)
651 for (i = 0; i < self->raw_length; i++)
645 Py_CLEAR(self->cache[i]);
652 Py_CLEAR(self->cache[i]);
646 free(self->cache);
653 free(self->cache);
647 self->cache = NULL;
654 self->cache = NULL;
648 }
655 }
649 if (self->offsets) {
656 if (self->offsets) {
650 free(self->offsets);
657 free(self->offsets);
651 self->offsets = NULL;
658 self->offsets = NULL;
652 }
659 }
653 if (self->nt) {
660 if (self->nt) {
654 free(self->nt);
661 free(self->nt);
655 self->nt = NULL;
662 self->nt = NULL;
656 }
663 }
657 Py_CLEAR(self->headrevs);
664 Py_CLEAR(self->headrevs);
658 }
665 }
659
666
660 static PyObject *index_clearcaches(indexObject *self)
667 static PyObject *index_clearcaches(indexObject *self)
661 {
668 {
662 _index_clearcaches(self);
669 _index_clearcaches(self);
663 self->ntlength = self->ntcapacity = 0;
670 self->ntlength = self->ntcapacity = 0;
664 self->ntdepth = self->ntsplits = 0;
671 self->ntdepth = self->ntsplits = 0;
665 self->ntrev = -1;
672 self->ntrev = -1;
666 self->ntlookups = self->ntmisses = 0;
673 self->ntlookups = self->ntmisses = 0;
667 Py_RETURN_NONE;
674 Py_RETURN_NONE;
668 }
675 }
669
676
670 static PyObject *index_stats(indexObject *self)
677 static PyObject *index_stats(indexObject *self)
671 {
678 {
672 PyObject *obj = PyDict_New();
679 PyObject *obj = PyDict_New();
673
680
674 if (obj == NULL)
681 if (obj == NULL)
675 return NULL;
682 return NULL;
676
683
677 #define istat(__n, __d) \
684 #define istat(__n, __d) \
678 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
685 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
679 goto bail;
686 goto bail;
680
687
681 if (self->added) {
688 if (self->added) {
682 Py_ssize_t len = PyList_GET_SIZE(self->added);
689 Py_ssize_t len = PyList_GET_SIZE(self->added);
683 if (PyDict_SetItemString(obj, "index entries added",
690 if (PyDict_SetItemString(obj, "index entries added",
684 PyInt_FromSsize_t(len)) == -1)
691 PyInt_FromSsize_t(len)) == -1)
685 goto bail;
692 goto bail;
686 }
693 }
687
694
688 if (self->raw_length != self->length - 1)
695 if (self->raw_length != self->length - 1)
689 istat(raw_length, "revs on disk");
696 istat(raw_length, "revs on disk");
690 istat(length, "revs in memory");
697 istat(length, "revs in memory");
691 istat(ntcapacity, "node trie capacity");
698 istat(ntcapacity, "node trie capacity");
692 istat(ntdepth, "node trie depth");
699 istat(ntdepth, "node trie depth");
693 istat(ntlength, "node trie count");
700 istat(ntlength, "node trie count");
694 istat(ntlookups, "node trie lookups");
701 istat(ntlookups, "node trie lookups");
695 istat(ntmisses, "node trie misses");
702 istat(ntmisses, "node trie misses");
696 istat(ntrev, "node trie last rev scanned");
703 istat(ntrev, "node trie last rev scanned");
697 istat(ntsplits, "node trie splits");
704 istat(ntsplits, "node trie splits");
698
705
699 #undef istat
706 #undef istat
700
707
701 return obj;
708 return obj;
702
709
703 bail:
710 bail:
704 Py_XDECREF(obj);
711 Py_XDECREF(obj);
705 return NULL;
712 return NULL;
706 }
713 }
707
714
708 /*
715 /*
709 * When we cache a list, we want to be sure the caller can't mutate
716 * When we cache a list, we want to be sure the caller can't mutate
710 * the cached copy.
717 * the cached copy.
711 */
718 */
712 static PyObject *list_copy(PyObject *list)
719 static PyObject *list_copy(PyObject *list)
713 {
720 {
714 Py_ssize_t len = PyList_GET_SIZE(list);
721 Py_ssize_t len = PyList_GET_SIZE(list);
715 PyObject *newlist = PyList_New(len);
722 PyObject *newlist = PyList_New(len);
716 Py_ssize_t i;
723 Py_ssize_t i;
717
724
718 if (newlist == NULL)
725 if (newlist == NULL)
719 return NULL;
726 return NULL;
720
727
721 for (i = 0; i < len; i++) {
728 for (i = 0; i < len; i++) {
722 PyObject *obj = PyList_GET_ITEM(list, i);
729 PyObject *obj = PyList_GET_ITEM(list, i);
723 Py_INCREF(obj);
730 Py_INCREF(obj);
724 PyList_SET_ITEM(newlist, i, obj);
731 PyList_SET_ITEM(newlist, i, obj);
725 }
732 }
726
733
727 return newlist;
734 return newlist;
728 }
735 }
729
736
730 static PyObject *index_headrevs(indexObject *self)
737 static PyObject *index_headrevs(indexObject *self)
731 {
738 {
732 Py_ssize_t i, len, addlen;
739 Py_ssize_t i, len, addlen;
733 char *nothead = NULL;
740 char *nothead = NULL;
734 PyObject *heads;
741 PyObject *heads;
735
742
736 if (self->headrevs)
743 if (self->headrevs)
737 return list_copy(self->headrevs);
744 return list_copy(self->headrevs);
738
745
739 len = index_length(self) - 1;
746 len = index_length(self) - 1;
740 heads = PyList_New(0);
747 heads = PyList_New(0);
741 if (heads == NULL)
748 if (heads == NULL)
742 goto bail;
749 goto bail;
743 if (len == 0) {
750 if (len == 0) {
744 PyObject *nullid = PyInt_FromLong(-1);
751 PyObject *nullid = PyInt_FromLong(-1);
745 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
752 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
746 Py_XDECREF(nullid);
753 Py_XDECREF(nullid);
747 goto bail;
754 goto bail;
748 }
755 }
749 goto done;
756 goto done;
750 }
757 }
751
758
752 nothead = calloc(len, 1);
759 nothead = calloc(len, 1);
753 if (nothead == NULL)
760 if (nothead == NULL)
754 goto bail;
761 goto bail;
755
762
756 for (i = 0; i < self->raw_length; i++) {
763 for (i = 0; i < self->raw_length; i++) {
757 const char *data = index_deref(self, i);
764 const char *data = index_deref(self, i);
758 int parent_1 = getbe32(data + 24);
765 int parent_1 = getbe32(data + 24);
759 int parent_2 = getbe32(data + 28);
766 int parent_2 = getbe32(data + 28);
760 if (parent_1 >= 0)
767 if (parent_1 >= 0)
761 nothead[parent_1] = 1;
768 nothead[parent_1] = 1;
762 if (parent_2 >= 0)
769 if (parent_2 >= 0)
763 nothead[parent_2] = 1;
770 nothead[parent_2] = 1;
764 }
771 }
765
772
766 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
773 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
767
774
768 for (i = 0; i < addlen; i++) {
775 for (i = 0; i < addlen; i++) {
769 PyObject *rev = PyList_GET_ITEM(self->added, i);
776 PyObject *rev = PyList_GET_ITEM(self->added, i);
770 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
777 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
771 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
778 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
772 long parent_1, parent_2;
779 long parent_1, parent_2;
773
780
774 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
781 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
775 PyErr_SetString(PyExc_TypeError,
782 PyErr_SetString(PyExc_TypeError,
776 "revlog parents are invalid");
783 "revlog parents are invalid");
777 goto bail;
784 goto bail;
778 }
785 }
779 parent_1 = PyInt_AS_LONG(p1);
786 parent_1 = PyInt_AS_LONG(p1);
780 parent_2 = PyInt_AS_LONG(p2);
787 parent_2 = PyInt_AS_LONG(p2);
781 if (parent_1 >= 0)
788 if (parent_1 >= 0)
782 nothead[parent_1] = 1;
789 nothead[parent_1] = 1;
783 if (parent_2 >= 0)
790 if (parent_2 >= 0)
784 nothead[parent_2] = 1;
791 nothead[parent_2] = 1;
785 }
792 }
786
793
787 for (i = 0; i < len; i++) {
794 for (i = 0; i < len; i++) {
788 PyObject *head;
795 PyObject *head;
789
796
790 if (nothead[i])
797 if (nothead[i])
791 continue;
798 continue;
792 head = PyInt_FromLong(i);
799 head = PyInt_FromLong(i);
793 if (head == NULL || PyList_Append(heads, head) == -1) {
800 if (head == NULL || PyList_Append(heads, head) == -1) {
794 Py_XDECREF(head);
801 Py_XDECREF(head);
795 goto bail;
802 goto bail;
796 }
803 }
797 }
804 }
798
805
799 done:
806 done:
800 self->headrevs = heads;
807 self->headrevs = heads;
801 free(nothead);
808 free(nothead);
802 return list_copy(self->headrevs);
809 return list_copy(self->headrevs);
803 bail:
810 bail:
804 Py_XDECREF(heads);
811 Py_XDECREF(heads);
805 free(nothead);
812 free(nothead);
806 return NULL;
813 return NULL;
807 }
814 }
808
815
809 static inline int nt_level(const char *node, Py_ssize_t level)
816 static inline int nt_level(const char *node, Py_ssize_t level)
810 {
817 {
811 int v = node[level>>1];
818 int v = node[level>>1];
812 if (!(level & 1))
819 if (!(level & 1))
813 v >>= 4;
820 v >>= 4;
814 return v & 0xf;
821 return v & 0xf;
815 }
822 }
816
823
817 /*
824 /*
818 * Return values:
825 * Return values:
819 *
826 *
820 * -4: match is ambiguous (multiple candidates)
827 * -4: match is ambiguous (multiple candidates)
821 * -2: not found
828 * -2: not found
822 * rest: valid rev
829 * rest: valid rev
823 */
830 */
824 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
831 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
825 int hex)
832 int hex)
826 {
833 {
827 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
834 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
828 int level, maxlevel, off;
835 int level, maxlevel, off;
829
836
830 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
837 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
831 return -1;
838 return -1;
832
839
833 if (self->nt == NULL)
840 if (self->nt == NULL)
834 return -2;
841 return -2;
835
842
836 if (hex)
843 if (hex)
837 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
844 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
838 else
845 else
839 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
846 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
840
847
841 for (level = off = 0; level < maxlevel; level++) {
848 for (level = off = 0; level < maxlevel; level++) {
842 int k = getnybble(node, level);
849 int k = getnybble(node, level);
843 nodetree *n = &self->nt[off];
850 nodetree *n = &self->nt[off];
844 int v = n->children[k];
851 int v = n->children[k];
845
852
846 if (v < 0) {
853 if (v < 0) {
847 const char *n;
854 const char *n;
848 Py_ssize_t i;
855 Py_ssize_t i;
849
856
850 v = -v - 1;
857 v = -v - 1;
851 n = index_node(self, v);
858 n = index_node(self, v);
852 if (n == NULL)
859 if (n == NULL)
853 return -2;
860 return -2;
854 for (i = level; i < maxlevel; i++)
861 for (i = level; i < maxlevel; i++)
855 if (getnybble(node, i) != nt_level(n, i))
862 if (getnybble(node, i) != nt_level(n, i))
856 return -2;
863 return -2;
857 return v;
864 return v;
858 }
865 }
859 if (v == 0)
866 if (v == 0)
860 return -2;
867 return -2;
861 off = v;
868 off = v;
862 }
869 }
863 /* multiple matches against an ambiguous prefix */
870 /* multiple matches against an ambiguous prefix */
864 return -4;
871 return -4;
865 }
872 }
866
873
867 static int nt_new(indexObject *self)
874 static int nt_new(indexObject *self)
868 {
875 {
869 if (self->ntlength == self->ntcapacity) {
876 if (self->ntlength == self->ntcapacity) {
870 self->ntcapacity *= 2;
877 self->ntcapacity *= 2;
871 self->nt = realloc(self->nt,
878 self->nt = realloc(self->nt,
872 self->ntcapacity * sizeof(nodetree));
879 self->ntcapacity * sizeof(nodetree));
873 if (self->nt == NULL) {
880 if (self->nt == NULL) {
874 PyErr_SetString(PyExc_MemoryError, "out of memory");
881 PyErr_SetString(PyExc_MemoryError, "out of memory");
875 return -1;
882 return -1;
876 }
883 }
877 memset(&self->nt[self->ntlength], 0,
884 memset(&self->nt[self->ntlength], 0,
878 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
885 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
879 }
886 }
880 return self->ntlength++;
887 return self->ntlength++;
881 }
888 }
882
889
883 static int nt_insert(indexObject *self, const char *node, int rev)
890 static int nt_insert(indexObject *self, const char *node, int rev)
884 {
891 {
885 int level = 0;
892 int level = 0;
886 int off = 0;
893 int off = 0;
887
894
888 while (level < 40) {
895 while (level < 40) {
889 int k = nt_level(node, level);
896 int k = nt_level(node, level);
890 nodetree *n;
897 nodetree *n;
891 int v;
898 int v;
892
899
893 n = &self->nt[off];
900 n = &self->nt[off];
894 v = n->children[k];
901 v = n->children[k];
895
902
896 if (v == 0) {
903 if (v == 0) {
897 n->children[k] = -rev - 1;
904 n->children[k] = -rev - 1;
898 return 0;
905 return 0;
899 }
906 }
900 if (v < 0) {
907 if (v < 0) {
901 const char *oldnode = index_node(self, -v - 1);
908 const char *oldnode = index_node(self, -v - 1);
902 int noff;
909 int noff;
903
910
904 if (!oldnode || !memcmp(oldnode, node, 20)) {
911 if (!oldnode || !memcmp(oldnode, node, 20)) {
905 n->children[k] = -rev - 1;
912 n->children[k] = -rev - 1;
906 return 0;
913 return 0;
907 }
914 }
908 noff = nt_new(self);
915 noff = nt_new(self);
909 if (noff == -1)
916 if (noff == -1)
910 return -1;
917 return -1;
911 /* self->nt may have been changed by realloc */
918 /* self->nt may have been changed by realloc */
912 self->nt[off].children[k] = noff;
919 self->nt[off].children[k] = noff;
913 off = noff;
920 off = noff;
914 n = &self->nt[off];
921 n = &self->nt[off];
915 n->children[nt_level(oldnode, ++level)] = v;
922 n->children[nt_level(oldnode, ++level)] = v;
916 if (level > self->ntdepth)
923 if (level > self->ntdepth)
917 self->ntdepth = level;
924 self->ntdepth = level;
918 self->ntsplits += 1;
925 self->ntsplits += 1;
919 } else {
926 } else {
920 level += 1;
927 level += 1;
921 off = v;
928 off = v;
922 }
929 }
923 }
930 }
924
931
925 return -1;
932 return -1;
926 }
933 }
927
934
928 static int nt_init(indexObject *self)
935 static int nt_init(indexObject *self)
929 {
936 {
930 if (self->nt == NULL) {
937 if (self->nt == NULL) {
931 if (self->raw_length > INT_MAX) {
938 if (self->raw_length > INT_MAX) {
932 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
939 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
933 return -1;
940 return -1;
934 }
941 }
935 self->ntcapacity = self->raw_length < 4
942 self->ntcapacity = self->raw_length < 4
936 ? 4 : (int)self->raw_length / 2;
943 ? 4 : (int)self->raw_length / 2;
937
944
938 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
945 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
939 if (self->nt == NULL) {
946 if (self->nt == NULL) {
940 PyErr_NoMemory();
947 PyErr_NoMemory();
941 return -1;
948 return -1;
942 }
949 }
943 self->ntlength = 1;
950 self->ntlength = 1;
944 self->ntrev = (int)index_length(self) - 1;
951 self->ntrev = (int)index_length(self) - 1;
945 self->ntlookups = 1;
952 self->ntlookups = 1;
946 self->ntmisses = 0;
953 self->ntmisses = 0;
947 if (nt_insert(self, nullid, INT_MAX) == -1)
954 if (nt_insert(self, nullid, INT_MAX) == -1)
948 return -1;
955 return -1;
949 }
956 }
950 return 0;
957 return 0;
951 }
958 }
952
959
953 /*
960 /*
954 * Return values:
961 * Return values:
955 *
962 *
956 * -3: error (exception set)
963 * -3: error (exception set)
957 * -2: not found (no exception set)
964 * -2: not found (no exception set)
958 * rest: valid rev
965 * rest: valid rev
959 */
966 */
960 static int index_find_node(indexObject *self,
967 static int index_find_node(indexObject *self,
961 const char *node, Py_ssize_t nodelen)
968 const char *node, Py_ssize_t nodelen)
962 {
969 {
963 int rev;
970 int rev;
964
971
965 self->ntlookups++;
972 self->ntlookups++;
966 rev = nt_find(self, node, nodelen, 0);
973 rev = nt_find(self, node, nodelen, 0);
967 if (rev >= -1)
974 if (rev >= -1)
968 return rev;
975 return rev;
969
976
970 if (nt_init(self) == -1)
977 if (nt_init(self) == -1)
971 return -3;
978 return -3;
972
979
973 /*
980 /*
974 * For the first handful of lookups, we scan the entire index,
981 * For the first handful of lookups, we scan the entire index,
975 * and cache only the matching nodes. This optimizes for cases
982 * and cache only the matching nodes. This optimizes for cases
976 * like "hg tip", where only a few nodes are accessed.
983 * like "hg tip", where only a few nodes are accessed.
977 *
984 *
978 * After that, we cache every node we visit, using a single
985 * After that, we cache every node we visit, using a single
979 * scan amortized over multiple lookups. This gives the best
986 * scan amortized over multiple lookups. This gives the best
980 * bulk performance, e.g. for "hg log".
987 * bulk performance, e.g. for "hg log".
981 */
988 */
982 if (self->ntmisses++ < 4) {
989 if (self->ntmisses++ < 4) {
983 for (rev = self->ntrev - 1; rev >= 0; rev--) {
990 for (rev = self->ntrev - 1; rev >= 0; rev--) {
984 const char *n = index_node(self, rev);
991 const char *n = index_node(self, rev);
985 if (n == NULL)
992 if (n == NULL)
986 return -2;
993 return -2;
987 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
994 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
988 if (nt_insert(self, n, rev) == -1)
995 if (nt_insert(self, n, rev) == -1)
989 return -3;
996 return -3;
990 break;
997 break;
991 }
998 }
992 }
999 }
993 } else {
1000 } else {
994 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1001 for (rev = self->ntrev - 1; rev >= 0; rev--) {
995 const char *n = index_node(self, rev);
1002 const char *n = index_node(self, rev);
996 if (n == NULL) {
1003 if (n == NULL) {
997 self->ntrev = rev + 1;
1004 self->ntrev = rev + 1;
998 return -2;
1005 return -2;
999 }
1006 }
1000 if (nt_insert(self, n, rev) == -1) {
1007 if (nt_insert(self, n, rev) == -1) {
1001 self->ntrev = rev + 1;
1008 self->ntrev = rev + 1;
1002 return -3;
1009 return -3;
1003 }
1010 }
1004 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1011 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1005 break;
1012 break;
1006 }
1013 }
1007 }
1014 }
1008 self->ntrev = rev;
1015 self->ntrev = rev;
1009 }
1016 }
1010
1017
1011 if (rev >= 0)
1018 if (rev >= 0)
1012 return rev;
1019 return rev;
1013 return -2;
1020 return -2;
1014 }
1021 }
1015
1022
1016 static PyObject *raise_revlog_error(void)
1023 static PyObject *raise_revlog_error(void)
1017 {
1024 {
1018 static PyObject *errclass;
1025 static PyObject *errclass;
1019 PyObject *mod = NULL, *errobj;
1026 PyObject *mod = NULL, *errobj;
1020
1027
1021 if (errclass == NULL) {
1028 if (errclass == NULL) {
1022 PyObject *dict;
1029 PyObject *dict;
1023
1030
1024 mod = PyImport_ImportModule("mercurial.error");
1031 mod = PyImport_ImportModule("mercurial.error");
1025 if (mod == NULL)
1032 if (mod == NULL)
1026 goto classfail;
1033 goto classfail;
1027
1034
1028 dict = PyModule_GetDict(mod);
1035 dict = PyModule_GetDict(mod);
1029 if (dict == NULL)
1036 if (dict == NULL)
1030 goto classfail;
1037 goto classfail;
1031
1038
1032 errclass = PyDict_GetItemString(dict, "RevlogError");
1039 errclass = PyDict_GetItemString(dict, "RevlogError");
1033 if (errclass == NULL) {
1040 if (errclass == NULL) {
1034 PyErr_SetString(PyExc_SystemError,
1041 PyErr_SetString(PyExc_SystemError,
1035 "could not find RevlogError");
1042 "could not find RevlogError");
1036 goto classfail;
1043 goto classfail;
1037 }
1044 }
1038 Py_INCREF(errclass);
1045 Py_INCREF(errclass);
1039 }
1046 }
1040
1047
1041 errobj = PyObject_CallFunction(errclass, NULL);
1048 errobj = PyObject_CallFunction(errclass, NULL);
1042 if (errobj == NULL)
1049 if (errobj == NULL)
1043 return NULL;
1050 return NULL;
1044 PyErr_SetObject(errclass, errobj);
1051 PyErr_SetObject(errclass, errobj);
1045 return errobj;
1052 return errobj;
1046
1053
1047 classfail:
1054 classfail:
1048 Py_XDECREF(mod);
1055 Py_XDECREF(mod);
1049 return NULL;
1056 return NULL;
1050 }
1057 }
1051
1058
1052 static PyObject *index_getitem(indexObject *self, PyObject *value)
1059 static PyObject *index_getitem(indexObject *self, PyObject *value)
1053 {
1060 {
1054 char *node;
1061 char *node;
1055 Py_ssize_t nodelen;
1062 Py_ssize_t nodelen;
1056 int rev;
1063 int rev;
1057
1064
1058 if (PyInt_Check(value))
1065 if (PyInt_Check(value))
1059 return index_get(self, PyInt_AS_LONG(value));
1066 return index_get(self, PyInt_AS_LONG(value));
1060
1067
1061 if (node_check(value, &node, &nodelen) == -1)
1068 if (node_check(value, &node, &nodelen) == -1)
1062 return NULL;
1069 return NULL;
1063 rev = index_find_node(self, node, nodelen);
1070 rev = index_find_node(self, node, nodelen);
1064 if (rev >= -1)
1071 if (rev >= -1)
1065 return PyInt_FromLong(rev);
1072 return PyInt_FromLong(rev);
1066 if (rev == -2)
1073 if (rev == -2)
1067 raise_revlog_error();
1074 raise_revlog_error();
1068 return NULL;
1075 return NULL;
1069 }
1076 }
1070
1077
1071 static int nt_partialmatch(indexObject *self, const char *node,
1078 static int nt_partialmatch(indexObject *self, const char *node,
1072 Py_ssize_t nodelen)
1079 Py_ssize_t nodelen)
1073 {
1080 {
1074 int rev;
1081 int rev;
1075
1082
1076 if (nt_init(self) == -1)
1083 if (nt_init(self) == -1)
1077 return -3;
1084 return -3;
1078
1085
1079 if (self->ntrev > 0) {
1086 if (self->ntrev > 0) {
1080 /* ensure that the radix tree is fully populated */
1087 /* ensure that the radix tree is fully populated */
1081 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1088 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1082 const char *n = index_node(self, rev);
1089 const char *n = index_node(self, rev);
1083 if (n == NULL)
1090 if (n == NULL)
1084 return -2;
1091 return -2;
1085 if (nt_insert(self, n, rev) == -1)
1092 if (nt_insert(self, n, rev) == -1)
1086 return -3;
1093 return -3;
1087 }
1094 }
1088 self->ntrev = rev;
1095 self->ntrev = rev;
1089 }
1096 }
1090
1097
1091 return nt_find(self, node, nodelen, 1);
1098 return nt_find(self, node, nodelen, 1);
1092 }
1099 }
1093
1100
1094 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1101 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1095 {
1102 {
1096 const char *fullnode;
1103 const char *fullnode;
1097 int nodelen;
1104 int nodelen;
1098 char *node;
1105 char *node;
1099 int rev, i;
1106 int rev, i;
1100
1107
1101 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1108 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1102 return NULL;
1109 return NULL;
1103
1110
1104 if (nodelen < 4) {
1111 if (nodelen < 4) {
1105 PyErr_SetString(PyExc_ValueError, "key too short");
1112 PyErr_SetString(PyExc_ValueError, "key too short");
1106 return NULL;
1113 return NULL;
1107 }
1114 }
1108
1115
1109 if (nodelen > 40) {
1116 if (nodelen > 40) {
1110 PyErr_SetString(PyExc_ValueError, "key too long");
1117 PyErr_SetString(PyExc_ValueError, "key too long");
1111 return NULL;
1118 return NULL;
1112 }
1119 }
1113
1120
1114 for (i = 0; i < nodelen; i++)
1121 for (i = 0; i < nodelen; i++)
1115 hexdigit(node, i);
1122 hexdigit(node, i);
1116 if (PyErr_Occurred()) {
1123 if (PyErr_Occurred()) {
1117 /* input contains non-hex characters */
1124 /* input contains non-hex characters */
1118 PyErr_Clear();
1125 PyErr_Clear();
1119 Py_RETURN_NONE;
1126 Py_RETURN_NONE;
1120 }
1127 }
1121
1128
1122 rev = nt_partialmatch(self, node, nodelen);
1129 rev = nt_partialmatch(self, node, nodelen);
1123
1130
1124 switch (rev) {
1131 switch (rev) {
1125 case -4:
1132 case -4:
1126 raise_revlog_error();
1133 raise_revlog_error();
1127 case -3:
1134 case -3:
1128 return NULL;
1135 return NULL;
1129 case -2:
1136 case -2:
1130 Py_RETURN_NONE;
1137 Py_RETURN_NONE;
1131 case -1:
1138 case -1:
1132 return PyString_FromStringAndSize(nullid, 20);
1139 return PyString_FromStringAndSize(nullid, 20);
1133 }
1140 }
1134
1141
1135 fullnode = index_node(self, rev);
1142 fullnode = index_node(self, rev);
1136 if (fullnode == NULL) {
1143 if (fullnode == NULL) {
1137 PyErr_Format(PyExc_IndexError,
1144 PyErr_Format(PyExc_IndexError,
1138 "could not access rev %d", rev);
1145 "could not access rev %d", rev);
1139 return NULL;
1146 return NULL;
1140 }
1147 }
1141 return PyString_FromStringAndSize(fullnode, 20);
1148 return PyString_FromStringAndSize(fullnode, 20);
1142 }
1149 }
1143
1150
1144 static PyObject *index_m_get(indexObject *self, PyObject *args)
1151 static PyObject *index_m_get(indexObject *self, PyObject *args)
1145 {
1152 {
1146 Py_ssize_t nodelen;
1153 Py_ssize_t nodelen;
1147 PyObject *val;
1154 PyObject *val;
1148 char *node;
1155 char *node;
1149 int rev;
1156 int rev;
1150
1157
1151 if (!PyArg_ParseTuple(args, "O", &val))
1158 if (!PyArg_ParseTuple(args, "O", &val))
1152 return NULL;
1159 return NULL;
1153 if (node_check(val, &node, &nodelen) == -1)
1160 if (node_check(val, &node, &nodelen) == -1)
1154 return NULL;
1161 return NULL;
1155 rev = index_find_node(self, node, nodelen);
1162 rev = index_find_node(self, node, nodelen);
1156 if (rev == -3)
1163 if (rev == -3)
1157 return NULL;
1164 return NULL;
1158 if (rev == -2)
1165 if (rev == -2)
1159 Py_RETURN_NONE;
1166 Py_RETURN_NONE;
1160 return PyInt_FromLong(rev);
1167 return PyInt_FromLong(rev);
1161 }
1168 }
1162
1169
1163 static int index_contains(indexObject *self, PyObject *value)
1170 static int index_contains(indexObject *self, PyObject *value)
1164 {
1171 {
1165 char *node;
1172 char *node;
1166 Py_ssize_t nodelen;
1173 Py_ssize_t nodelen;
1167
1174
1168 if (PyInt_Check(value)) {
1175 if (PyInt_Check(value)) {
1169 long rev = PyInt_AS_LONG(value);
1176 long rev = PyInt_AS_LONG(value);
1170 return rev >= -1 && rev < index_length(self);
1177 return rev >= -1 && rev < index_length(self);
1171 }
1178 }
1172
1179
1173 if (node_check(value, &node, &nodelen) == -1)
1180 if (node_check(value, &node, &nodelen) == -1)
1174 return -1;
1181 return -1;
1175
1182
1176 switch (index_find_node(self, node, nodelen)) {
1183 switch (index_find_node(self, node, nodelen)) {
1177 case -3:
1184 case -3:
1178 return -1;
1185 return -1;
1179 case -2:
1186 case -2:
1180 return 0;
1187 return 0;
1181 default:
1188 default:
1182 return 1;
1189 return 1;
1183 }
1190 }
1184 }
1191 }
1185
1192
1186 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1193 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1187 {
1194 {
1188 if (rev >= self->length - 1) {
1195 if (rev >= self->length - 1) {
1189 PyObject *tuple = PyList_GET_ITEM(self->added,
1196 PyObject *tuple = PyList_GET_ITEM(self->added,
1190 rev - self->length + 1);
1197 rev - self->length + 1);
1191 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1198 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1192 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1199 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1193 } else {
1200 } else {
1194 const char *data = index_deref(self, rev);
1201 const char *data = index_deref(self, rev);
1195 ps[0] = getbe32(data + 24);
1202 ps[0] = getbe32(data + 24);
1196 ps[1] = getbe32(data + 28);
1203 ps[1] = getbe32(data + 28);
1197 }
1204 }
1198 }
1205 }
1199
1206
1200 typedef uint64_t bitmask;
1207 typedef uint64_t bitmask;
1201
1208
1202 /*
1209 /*
1203 * Given a disjoint set of revs, return all candidates for the
1210 * Given a disjoint set of revs, return all candidates for the
1204 * greatest common ancestor. In revset notation, this is the set
1211 * greatest common ancestor. In revset notation, this is the set
1205 * "heads(::a and ::b and ...)"
1212 * "heads(::a and ::b and ...)"
1206 */
1213 */
1207 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1214 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1208 int revcount)
1215 int revcount)
1209 {
1216 {
1210 const bitmask allseen = (1ull << revcount) - 1;
1217 const bitmask allseen = (1ull << revcount) - 1;
1211 const bitmask poison = 1ull << revcount;
1218 const bitmask poison = 1ull << revcount;
1212 PyObject *gca = PyList_New(0);
1219 PyObject *gca = PyList_New(0);
1213 int i, v, interesting;
1220 int i, v, interesting;
1214 int maxrev = -1;
1221 int maxrev = -1;
1215 long sp;
1222 long sp;
1216 bitmask *seen;
1223 bitmask *seen;
1217
1224
1218 if (gca == NULL)
1225 if (gca == NULL)
1219 return PyErr_NoMemory();
1226 return PyErr_NoMemory();
1220
1227
1221 for (i = 0; i < revcount; i++) {
1228 for (i = 0; i < revcount; i++) {
1222 if (revs[i] > maxrev)
1229 if (revs[i] > maxrev)
1223 maxrev = revs[i];
1230 maxrev = revs[i];
1224 }
1231 }
1225
1232
1226 seen = calloc(sizeof(*seen), maxrev + 1);
1233 seen = calloc(sizeof(*seen), maxrev + 1);
1227 if (seen == NULL) {
1234 if (seen == NULL) {
1228 Py_DECREF(gca);
1235 Py_DECREF(gca);
1229 return PyErr_NoMemory();
1236 return PyErr_NoMemory();
1230 }
1237 }
1231
1238
1232 for (i = 0; i < revcount; i++)
1239 for (i = 0; i < revcount; i++)
1233 seen[revs[i]] = 1ull << i;
1240 seen[revs[i]] = 1ull << i;
1234
1241
1235 interesting = revcount;
1242 interesting = revcount;
1236
1243
1237 for (v = maxrev; v >= 0 && interesting; v--) {
1244 for (v = maxrev; v >= 0 && interesting; v--) {
1238 long sv = seen[v];
1245 long sv = seen[v];
1239 int parents[2];
1246 int parents[2];
1240
1247
1241 if (!sv)
1248 if (!sv)
1242 continue;
1249 continue;
1243
1250
1244 if (sv < poison) {
1251 if (sv < poison) {
1245 interesting -= 1;
1252 interesting -= 1;
1246 if (sv == allseen) {
1253 if (sv == allseen) {
1247 PyObject *obj = PyInt_FromLong(v);
1254 PyObject *obj = PyInt_FromLong(v);
1248 if (obj == NULL)
1255 if (obj == NULL)
1249 goto bail;
1256 goto bail;
1250 if (PyList_Append(gca, obj) == -1) {
1257 if (PyList_Append(gca, obj) == -1) {
1251 Py_DECREF(obj);
1258 Py_DECREF(obj);
1252 goto bail;
1259 goto bail;
1253 }
1260 }
1254 sv |= poison;
1261 sv |= poison;
1255 for (i = 0; i < revcount; i++) {
1262 for (i = 0; i < revcount; i++) {
1256 if (revs[i] == v)
1263 if (revs[i] == v)
1257 goto done;
1264 goto done;
1258 }
1265 }
1259 }
1266 }
1260 }
1267 }
1261 index_get_parents(self, v, parents);
1268 index_get_parents(self, v, parents);
1262
1269
1263 for (i = 0; i < 2; i++) {
1270 for (i = 0; i < 2; i++) {
1264 int p = parents[i];
1271 int p = parents[i];
1265 if (p == -1)
1272 if (p == -1)
1266 continue;
1273 continue;
1267 sp = seen[p];
1274 sp = seen[p];
1268 if (sv < poison) {
1275 if (sv < poison) {
1269 if (sp == 0) {
1276 if (sp == 0) {
1270 seen[p] = sv;
1277 seen[p] = sv;
1271 interesting++;
1278 interesting++;
1272 }
1279 }
1273 else if (sp != sv)
1280 else if (sp != sv)
1274 seen[p] |= sv;
1281 seen[p] |= sv;
1275 } else {
1282 } else {
1276 if (sp && sp < poison)
1283 if (sp && sp < poison)
1277 interesting--;
1284 interesting--;
1278 seen[p] = sv;
1285 seen[p] = sv;
1279 }
1286 }
1280 }
1287 }
1281 }
1288 }
1282
1289
1283 done:
1290 done:
1284 free(seen);
1291 free(seen);
1285 return gca;
1292 return gca;
1286 bail:
1293 bail:
1287 free(seen);
1294 free(seen);
1288 Py_XDECREF(gca);
1295 Py_XDECREF(gca);
1289 return NULL;
1296 return NULL;
1290 }
1297 }
1291
1298
1292 /*
1299 /*
1293 * Given a disjoint set of revs, return the subset with the longest
1300 * Given a disjoint set of revs, return the subset with the longest
1294 * path to the root.
1301 * path to the root.
1295 */
1302 */
1296 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1303 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1297 {
1304 {
1298 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1305 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1299 static const Py_ssize_t capacity = 24;
1306 static const Py_ssize_t capacity = 24;
1300 int *depth, *interesting = NULL;
1307 int *depth, *interesting = NULL;
1301 int i, j, v, ninteresting;
1308 int i, j, v, ninteresting;
1302 PyObject *dict = NULL, *keys = NULL;
1309 PyObject *dict = NULL, *keys = NULL;
1303 long *seen = NULL;
1310 long *seen = NULL;
1304 int maxrev = -1;
1311 int maxrev = -1;
1305 long final;
1312 long final;
1306
1313
1307 if (revcount > capacity) {
1314 if (revcount > capacity) {
1308 PyErr_Format(PyExc_OverflowError,
1315 PyErr_Format(PyExc_OverflowError,
1309 "bitset size (%ld) > capacity (%ld)",
1316 "bitset size (%ld) > capacity (%ld)",
1310 (long)revcount, (long)capacity);
1317 (long)revcount, (long)capacity);
1311 return NULL;
1318 return NULL;
1312 }
1319 }
1313
1320
1314 for (i = 0; i < revcount; i++) {
1321 for (i = 0; i < revcount; i++) {
1315 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1322 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1316 if (n > maxrev)
1323 if (n > maxrev)
1317 maxrev = n;
1324 maxrev = n;
1318 }
1325 }
1319
1326
1320 depth = calloc(sizeof(*depth), maxrev + 1);
1327 depth = calloc(sizeof(*depth), maxrev + 1);
1321 if (depth == NULL)
1328 if (depth == NULL)
1322 return PyErr_NoMemory();
1329 return PyErr_NoMemory();
1323
1330
1324 seen = calloc(sizeof(*seen), maxrev + 1);
1331 seen = calloc(sizeof(*seen), maxrev + 1);
1325 if (seen == NULL) {
1332 if (seen == NULL) {
1326 PyErr_NoMemory();
1333 PyErr_NoMemory();
1327 goto bail;
1334 goto bail;
1328 }
1335 }
1329
1336
1330 interesting = calloc(sizeof(*interesting), 2 << revcount);
1337 interesting = calloc(sizeof(*interesting), 2 << revcount);
1331 if (interesting == NULL) {
1338 if (interesting == NULL) {
1332 PyErr_NoMemory();
1339 PyErr_NoMemory();
1333 goto bail;
1340 goto bail;
1334 }
1341 }
1335
1342
1336 if (PyList_Sort(revs) == -1)
1343 if (PyList_Sort(revs) == -1)
1337 goto bail;
1344 goto bail;
1338
1345
1339 for (i = 0; i < revcount; i++) {
1346 for (i = 0; i < revcount; i++) {
1340 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1347 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1341 long b = 1l << i;
1348 long b = 1l << i;
1342 depth[n] = 1;
1349 depth[n] = 1;
1343 seen[n] = b;
1350 seen[n] = b;
1344 interesting[b] = 1;
1351 interesting[b] = 1;
1345 }
1352 }
1346
1353
1347 ninteresting = (int)revcount;
1354 ninteresting = (int)revcount;
1348
1355
1349 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1356 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1350 int dv = depth[v];
1357 int dv = depth[v];
1351 int parents[2];
1358 int parents[2];
1352 long sv;
1359 long sv;
1353
1360
1354 if (dv == 0)
1361 if (dv == 0)
1355 continue;
1362 continue;
1356
1363
1357 sv = seen[v];
1364 sv = seen[v];
1358 index_get_parents(self, v, parents);
1365 index_get_parents(self, v, parents);
1359
1366
1360 for (i = 0; i < 2; i++) {
1367 for (i = 0; i < 2; i++) {
1361 int p = parents[i];
1368 int p = parents[i];
1362 long nsp, sp;
1369 long nsp, sp;
1363 int dp;
1370 int dp;
1364
1371
1365 if (p == -1)
1372 if (p == -1)
1366 continue;
1373 continue;
1367
1374
1368 dp = depth[p];
1375 dp = depth[p];
1369 nsp = sp = seen[p];
1376 nsp = sp = seen[p];
1370 if (dp <= dv) {
1377 if (dp <= dv) {
1371 depth[p] = dv + 1;
1378 depth[p] = dv + 1;
1372 if (sp != sv) {
1379 if (sp != sv) {
1373 interesting[sv] += 1;
1380 interesting[sv] += 1;
1374 nsp = seen[p] = sv;
1381 nsp = seen[p] = sv;
1375 if (sp) {
1382 if (sp) {
1376 interesting[sp] -= 1;
1383 interesting[sp] -= 1;
1377 if (interesting[sp] == 0)
1384 if (interesting[sp] == 0)
1378 ninteresting -= 1;
1385 ninteresting -= 1;
1379 }
1386 }
1380 }
1387 }
1381 }
1388 }
1382 else if (dv == dp - 1) {
1389 else if (dv == dp - 1) {
1383 nsp = sp | sv;
1390 nsp = sp | sv;
1384 if (nsp == sp)
1391 if (nsp == sp)
1385 continue;
1392 continue;
1386 seen[p] = nsp;
1393 seen[p] = nsp;
1387 interesting[sp] -= 1;
1394 interesting[sp] -= 1;
1388 if (interesting[sp] == 0 && interesting[nsp] > 0)
1395 if (interesting[sp] == 0 && interesting[nsp] > 0)
1389 ninteresting -= 1;
1396 ninteresting -= 1;
1390 interesting[nsp] += 1;
1397 interesting[nsp] += 1;
1391 }
1398 }
1392 }
1399 }
1393 interesting[sv] -= 1;
1400 interesting[sv] -= 1;
1394 if (interesting[sv] == 0)
1401 if (interesting[sv] == 0)
1395 ninteresting -= 1;
1402 ninteresting -= 1;
1396 }
1403 }
1397
1404
1398 final = 0;
1405 final = 0;
1399 j = ninteresting;
1406 j = ninteresting;
1400 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1407 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1401 if (interesting[i] == 0)
1408 if (interesting[i] == 0)
1402 continue;
1409 continue;
1403 final |= i;
1410 final |= i;
1404 j -= 1;
1411 j -= 1;
1405 }
1412 }
1406 if (final == 0) {
1413 if (final == 0) {
1407 keys = PyList_New(0);
1414 keys = PyList_New(0);
1408 goto bail;
1415 goto bail;
1409 }
1416 }
1410
1417
1411 dict = PyDict_New();
1418 dict = PyDict_New();
1412 if (dict == NULL)
1419 if (dict == NULL)
1413 goto bail;
1420 goto bail;
1414
1421
1415 for (i = 0; i < revcount; i++) {
1422 for (i = 0; i < revcount; i++) {
1416 PyObject *key;
1423 PyObject *key;
1417
1424
1418 if ((final & (1 << i)) == 0)
1425 if ((final & (1 << i)) == 0)
1419 continue;
1426 continue;
1420
1427
1421 key = PyList_GET_ITEM(revs, i);
1428 key = PyList_GET_ITEM(revs, i);
1422 Py_INCREF(key);
1429 Py_INCREF(key);
1423 Py_INCREF(Py_None);
1430 Py_INCREF(Py_None);
1424 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1431 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1425 Py_DECREF(key);
1432 Py_DECREF(key);
1426 Py_DECREF(Py_None);
1433 Py_DECREF(Py_None);
1427 goto bail;
1434 goto bail;
1428 }
1435 }
1429 }
1436 }
1430
1437
1431 keys = PyDict_Keys(dict);
1438 keys = PyDict_Keys(dict);
1432
1439
1433 bail:
1440 bail:
1434 free(depth);
1441 free(depth);
1435 free(seen);
1442 free(seen);
1436 free(interesting);
1443 free(interesting);
1437 Py_XDECREF(dict);
1444 Py_XDECREF(dict);
1438
1445
1439 return keys;
1446 return keys;
1440 }
1447 }
1441
1448
1442 /*
1449 /*
1443 * Given a (possibly overlapping) set of revs, return the greatest
1450 * Given a (possibly overlapping) set of revs, return the greatest
1444 * common ancestors: those with the longest path to the root.
1451 * common ancestors: those with the longest path to the root.
1445 */
1452 */
1446 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1453 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1447 {
1454 {
1448 PyObject *ret = NULL, *gca = NULL;
1455 PyObject *ret = NULL, *gca = NULL;
1449 Py_ssize_t argcount, i, len;
1456 Py_ssize_t argcount, i, len;
1450 bitmask repeat = 0;
1457 bitmask repeat = 0;
1451 int revcount = 0;
1458 int revcount = 0;
1452 int *revs;
1459 int *revs;
1453
1460
1454 argcount = PySequence_Length(args);
1461 argcount = PySequence_Length(args);
1455 revs = malloc(argcount * sizeof(*revs));
1462 revs = malloc(argcount * sizeof(*revs));
1456 if (argcount > 0 && revs == NULL)
1463 if (argcount > 0 && revs == NULL)
1457 return PyErr_NoMemory();
1464 return PyErr_NoMemory();
1458 len = index_length(self) - 1;
1465 len = index_length(self) - 1;
1459
1466
1460 for (i = 0; i < argcount; i++) {
1467 for (i = 0; i < argcount; i++) {
1461 static const int capacity = 24;
1468 static const int capacity = 24;
1462 PyObject *obj = PySequence_GetItem(args, i);
1469 PyObject *obj = PySequence_GetItem(args, i);
1463 bitmask x;
1470 bitmask x;
1464 long val;
1471 long val;
1465
1472
1466 if (!PyInt_Check(obj)) {
1473 if (!PyInt_Check(obj)) {
1467 PyErr_SetString(PyExc_TypeError,
1474 PyErr_SetString(PyExc_TypeError,
1468 "arguments must all be ints");
1475 "arguments must all be ints");
1469 goto bail;
1476 goto bail;
1470 }
1477 }
1471 val = PyInt_AsLong(obj);
1478 val = PyInt_AsLong(obj);
1472 if (val == -1) {
1479 if (val == -1) {
1473 ret = PyList_New(0);
1480 ret = PyList_New(0);
1474 goto done;
1481 goto done;
1475 }
1482 }
1476 if (val < 0 || val >= len) {
1483 if (val < 0 || val >= len) {
1477 PyErr_SetString(PyExc_IndexError,
1484 PyErr_SetString(PyExc_IndexError,
1478 "index out of range");
1485 "index out of range");
1479 goto bail;
1486 goto bail;
1480 }
1487 }
1481 /* this cheesy bloom filter lets us avoid some more
1488 /* this cheesy bloom filter lets us avoid some more
1482 * expensive duplicate checks in the common set-is-disjoint
1489 * expensive duplicate checks in the common set-is-disjoint
1483 * case */
1490 * case */
1484 x = 1ull << (val & 0x3f);
1491 x = 1ull << (val & 0x3f);
1485 if (repeat & x) {
1492 if (repeat & x) {
1486 int k;
1493 int k;
1487 for (k = 0; k < revcount; k++) {
1494 for (k = 0; k < revcount; k++) {
1488 if (val == revs[k])
1495 if (val == revs[k])
1489 goto duplicate;
1496 goto duplicate;
1490 }
1497 }
1491 }
1498 }
1492 else repeat |= x;
1499 else repeat |= x;
1493 if (revcount >= capacity) {
1500 if (revcount >= capacity) {
1494 PyErr_Format(PyExc_OverflowError,
1501 PyErr_Format(PyExc_OverflowError,
1495 "bitset size (%d) > capacity (%d)",
1502 "bitset size (%d) > capacity (%d)",
1496 revcount, capacity);
1503 revcount, capacity);
1497 goto bail;
1504 goto bail;
1498 }
1505 }
1499 revs[revcount++] = (int)val;
1506 revs[revcount++] = (int)val;
1500 duplicate:;
1507 duplicate:;
1501 }
1508 }
1502
1509
1503 if (revcount == 0) {
1510 if (revcount == 0) {
1504 ret = PyList_New(0);
1511 ret = PyList_New(0);
1505 goto done;
1512 goto done;
1506 }
1513 }
1507 if (revcount == 1) {
1514 if (revcount == 1) {
1508 PyObject *obj;
1515 PyObject *obj;
1509 ret = PyList_New(1);
1516 ret = PyList_New(1);
1510 if (ret == NULL)
1517 if (ret == NULL)
1511 goto bail;
1518 goto bail;
1512 obj = PyInt_FromLong(revs[0]);
1519 obj = PyInt_FromLong(revs[0]);
1513 if (obj == NULL)
1520 if (obj == NULL)
1514 goto bail;
1521 goto bail;
1515 PyList_SET_ITEM(ret, 0, obj);
1522 PyList_SET_ITEM(ret, 0, obj);
1516 goto done;
1523 goto done;
1517 }
1524 }
1518
1525
1519 gca = find_gca_candidates(self, revs, revcount);
1526 gca = find_gca_candidates(self, revs, revcount);
1520 if (gca == NULL)
1527 if (gca == NULL)
1521 goto bail;
1528 goto bail;
1522
1529
1523 if (PyList_GET_SIZE(gca) <= 1) {
1530 if (PyList_GET_SIZE(gca) <= 1) {
1524 ret = gca;
1531 ret = gca;
1525 Py_INCREF(gca);
1532 Py_INCREF(gca);
1526 }
1533 }
1527 else ret = find_deepest(self, gca);
1534 else ret = find_deepest(self, gca);
1528
1535
1529 done:
1536 done:
1530 free(revs);
1537 free(revs);
1531 Py_XDECREF(gca);
1538 Py_XDECREF(gca);
1532
1539
1533 return ret;
1540 return ret;
1534
1541
1535 bail:
1542 bail:
1536 free(revs);
1543 free(revs);
1537 Py_XDECREF(gca);
1544 Py_XDECREF(gca);
1538 Py_XDECREF(ret);
1545 Py_XDECREF(ret);
1539 return NULL;
1546 return NULL;
1540 }
1547 }
1541
1548
1542 /*
1549 /*
1543 * Given a (possibly overlapping) set of revs, return all the
1550 * Given a (possibly overlapping) set of revs, return all the
1544 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1551 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1545 */
1552 */
1546 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1553 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1547 {
1554 {
1548 PyObject *ret = NULL;
1555 PyObject *ret = NULL;
1549 Py_ssize_t argcount, i, len;
1556 Py_ssize_t argcount, i, len;
1550 bitmask repeat = 0;
1557 bitmask repeat = 0;
1551 int revcount = 0;
1558 int revcount = 0;
1552 int *revs;
1559 int *revs;
1553
1560
1554 argcount = PySequence_Length(args);
1561 argcount = PySequence_Length(args);
1555 revs = malloc(argcount * sizeof(*revs));
1562 revs = malloc(argcount * sizeof(*revs));
1556 if (argcount > 0 && revs == NULL)
1563 if (argcount > 0 && revs == NULL)
1557 return PyErr_NoMemory();
1564 return PyErr_NoMemory();
1558 len = index_length(self) - 1;
1565 len = index_length(self) - 1;
1559
1566
1560 for (i = 0; i < argcount; i++) {
1567 for (i = 0; i < argcount; i++) {
1561 static const int capacity = 24;
1568 static const int capacity = 24;
1562 PyObject *obj = PySequence_GetItem(args, i);
1569 PyObject *obj = PySequence_GetItem(args, i);
1563 bitmask x;
1570 bitmask x;
1564 long val;
1571 long val;
1565
1572
1566 if (!PyInt_Check(obj)) {
1573 if (!PyInt_Check(obj)) {
1567 PyErr_SetString(PyExc_TypeError,
1574 PyErr_SetString(PyExc_TypeError,
1568 "arguments must all be ints");
1575 "arguments must all be ints");
1569 goto bail;
1576 goto bail;
1570 }
1577 }
1571 val = PyInt_AsLong(obj);
1578 val = PyInt_AsLong(obj);
1572 if (val == -1) {
1579 if (val == -1) {
1573 ret = PyList_New(0);
1580 ret = PyList_New(0);
1574 goto done;
1581 goto done;
1575 }
1582 }
1576 if (val < 0 || val >= len) {
1583 if (val < 0 || val >= len) {
1577 PyErr_SetString(PyExc_IndexError,
1584 PyErr_SetString(PyExc_IndexError,
1578 "index out of range");
1585 "index out of range");
1579 goto bail;
1586 goto bail;
1580 }
1587 }
1581 /* this cheesy bloom filter lets us avoid some more
1588 /* this cheesy bloom filter lets us avoid some more
1582 * expensive duplicate checks in the common set-is-disjoint
1589 * expensive duplicate checks in the common set-is-disjoint
1583 * case */
1590 * case */
1584 x = 1ull << (val & 0x3f);
1591 x = 1ull << (val & 0x3f);
1585 if (repeat & x) {
1592 if (repeat & x) {
1586 int k;
1593 int k;
1587 for (k = 0; k < revcount; k++) {
1594 for (k = 0; k < revcount; k++) {
1588 if (val == revs[k])
1595 if (val == revs[k])
1589 goto duplicate;
1596 goto duplicate;
1590 }
1597 }
1591 }
1598 }
1592 else repeat |= x;
1599 else repeat |= x;
1593 if (revcount >= capacity) {
1600 if (revcount >= capacity) {
1594 PyErr_Format(PyExc_OverflowError,
1601 PyErr_Format(PyExc_OverflowError,
1595 "bitset size (%d) > capacity (%d)",
1602 "bitset size (%d) > capacity (%d)",
1596 revcount, capacity);
1603 revcount, capacity);
1597 goto bail;
1604 goto bail;
1598 }
1605 }
1599 revs[revcount++] = (int)val;
1606 revs[revcount++] = (int)val;
1600 duplicate:;
1607 duplicate:;
1601 }
1608 }
1602
1609
1603 if (revcount == 0) {
1610 if (revcount == 0) {
1604 ret = PyList_New(0);
1611 ret = PyList_New(0);
1605 goto done;
1612 goto done;
1606 }
1613 }
1607 if (revcount == 1) {
1614 if (revcount == 1) {
1608 PyObject *obj;
1615 PyObject *obj;
1609 ret = PyList_New(1);
1616 ret = PyList_New(1);
1610 if (ret == NULL)
1617 if (ret == NULL)
1611 goto bail;
1618 goto bail;
1612 obj = PyInt_FromLong(revs[0]);
1619 obj = PyInt_FromLong(revs[0]);
1613 if (obj == NULL)
1620 if (obj == NULL)
1614 goto bail;
1621 goto bail;
1615 PyList_SET_ITEM(ret, 0, obj);
1622 PyList_SET_ITEM(ret, 0, obj);
1616 goto done;
1623 goto done;
1617 }
1624 }
1618
1625
1619 ret = find_gca_candidates(self, revs, revcount);
1626 ret = find_gca_candidates(self, revs, revcount);
1620 if (ret == NULL)
1627 if (ret == NULL)
1621 goto bail;
1628 goto bail;
1622
1629
1623 done:
1630 done:
1624 free(revs);
1631 free(revs);
1625 return ret;
1632 return ret;
1626
1633
1627 bail:
1634 bail:
1628 free(revs);
1635 free(revs);
1629 Py_XDECREF(ret);
1636 Py_XDECREF(ret);
1630 return NULL;
1637 return NULL;
1631 }
1638 }
1632
1639
1633 /*
1640 /*
1634 * Invalidate any trie entries introduced by added revs.
1641 * Invalidate any trie entries introduced by added revs.
1635 */
1642 */
1636 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1643 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1637 {
1644 {
1638 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1645 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1639
1646
1640 for (i = start; i < len; i++) {
1647 for (i = start; i < len; i++) {
1641 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1648 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1642 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1649 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1643
1650
1644 nt_insert(self, PyString_AS_STRING(node), -1);
1651 nt_insert(self, PyString_AS_STRING(node), -1);
1645 }
1652 }
1646
1653
1647 if (start == 0)
1654 if (start == 0)
1648 Py_CLEAR(self->added);
1655 Py_CLEAR(self->added);
1649 }
1656 }
1650
1657
1651 /*
1658 /*
1652 * Delete a numeric range of revs, which must be at the end of the
1659 * Delete a numeric range of revs, which must be at the end of the
1653 * range, but exclude the sentinel nullid entry.
1660 * range, but exclude the sentinel nullid entry.
1654 */
1661 */
1655 static int index_slice_del(indexObject *self, PyObject *item)
1662 static int index_slice_del(indexObject *self, PyObject *item)
1656 {
1663 {
1657 Py_ssize_t start, stop, step, slicelength;
1664 Py_ssize_t start, stop, step, slicelength;
1658 Py_ssize_t length = index_length(self);
1665 Py_ssize_t length = index_length(self);
1659 int ret = 0;
1666 int ret = 0;
1660
1667
1661 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1668 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1662 &start, &stop, &step, &slicelength) < 0)
1669 &start, &stop, &step, &slicelength) < 0)
1663 return -1;
1670 return -1;
1664
1671
1665 if (slicelength <= 0)
1672 if (slicelength <= 0)
1666 return 0;
1673 return 0;
1667
1674
1668 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1675 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1669 stop = start;
1676 stop = start;
1670
1677
1671 if (step < 0) {
1678 if (step < 0) {
1672 stop = start + 1;
1679 stop = start + 1;
1673 start = stop + step*(slicelength - 1) - 1;
1680 start = stop + step*(slicelength - 1) - 1;
1674 step = -step;
1681 step = -step;
1675 }
1682 }
1676
1683
1677 if (step != 1) {
1684 if (step != 1) {
1678 PyErr_SetString(PyExc_ValueError,
1685 PyErr_SetString(PyExc_ValueError,
1679 "revlog index delete requires step size of 1");
1686 "revlog index delete requires step size of 1");
1680 return -1;
1687 return -1;
1681 }
1688 }
1682
1689
1683 if (stop != length - 1) {
1690 if (stop != length - 1) {
1684 PyErr_SetString(PyExc_IndexError,
1691 PyErr_SetString(PyExc_IndexError,
1685 "revlog index deletion indices are invalid");
1692 "revlog index deletion indices are invalid");
1686 return -1;
1693 return -1;
1687 }
1694 }
1688
1695
1689 if (start < self->length - 1) {
1696 if (start < self->length - 1) {
1690 if (self->nt) {
1697 if (self->nt) {
1691 Py_ssize_t i;
1698 Py_ssize_t i;
1692
1699
1693 for (i = start + 1; i < self->length - 1; i++) {
1700 for (i = start + 1; i < self->length - 1; i++) {
1694 const char *node = index_node(self, i);
1701 const char *node = index_node(self, i);
1695
1702
1696 if (node)
1703 if (node)
1697 nt_insert(self, node, -1);
1704 nt_insert(self, node, -1);
1698 }
1705 }
1699 if (self->added)
1706 if (self->added)
1700 nt_invalidate_added(self, 0);
1707 nt_invalidate_added(self, 0);
1701 if (self->ntrev > start)
1708 if (self->ntrev > start)
1702 self->ntrev = (int)start;
1709 self->ntrev = (int)start;
1703 }
1710 }
1704 self->length = start + 1;
1711 self->length = start + 1;
1705 if (start < self->raw_length) {
1712 if (start < self->raw_length) {
1706 if (self->cache) {
1713 if (self->cache) {
1707 Py_ssize_t i;
1714 Py_ssize_t i;
1708 for (i = start; i < self->raw_length; i++)
1715 for (i = start; i < self->raw_length; i++)
1709 Py_CLEAR(self->cache[i]);
1716 Py_CLEAR(self->cache[i]);
1710 }
1717 }
1711 self->raw_length = start;
1718 self->raw_length = start;
1712 }
1719 }
1713 goto done;
1720 goto done;
1714 }
1721 }
1715
1722
1716 if (self->nt) {
1723 if (self->nt) {
1717 nt_invalidate_added(self, start - self->length + 1);
1724 nt_invalidate_added(self, start - self->length + 1);
1718 if (self->ntrev > start)
1725 if (self->ntrev > start)
1719 self->ntrev = (int)start;
1726 self->ntrev = (int)start;
1720 }
1727 }
1721 if (self->added)
1728 if (self->added)
1722 ret = PyList_SetSlice(self->added, start - self->length + 1,
1729 ret = PyList_SetSlice(self->added, start - self->length + 1,
1723 PyList_GET_SIZE(self->added), NULL);
1730 PyList_GET_SIZE(self->added), NULL);
1724 done:
1731 done:
1725 Py_CLEAR(self->headrevs);
1732 Py_CLEAR(self->headrevs);
1726 return ret;
1733 return ret;
1727 }
1734 }
1728
1735
1729 /*
1736 /*
1730 * Supported ops:
1737 * Supported ops:
1731 *
1738 *
1732 * slice deletion
1739 * slice deletion
1733 * string assignment (extend node->rev mapping)
1740 * string assignment (extend node->rev mapping)
1734 * string deletion (shrink node->rev mapping)
1741 * string deletion (shrink node->rev mapping)
1735 */
1742 */
1736 static int index_assign_subscript(indexObject *self, PyObject *item,
1743 static int index_assign_subscript(indexObject *self, PyObject *item,
1737 PyObject *value)
1744 PyObject *value)
1738 {
1745 {
1739 char *node;
1746 char *node;
1740 Py_ssize_t nodelen;
1747 Py_ssize_t nodelen;
1741 long rev;
1748 long rev;
1742
1749
1743 if (PySlice_Check(item) && value == NULL)
1750 if (PySlice_Check(item) && value == NULL)
1744 return index_slice_del(self, item);
1751 return index_slice_del(self, item);
1745
1752
1746 if (node_check(item, &node, &nodelen) == -1)
1753 if (node_check(item, &node, &nodelen) == -1)
1747 return -1;
1754 return -1;
1748
1755
1749 if (value == NULL)
1756 if (value == NULL)
1750 return self->nt ? nt_insert(self, node, -1) : 0;
1757 return self->nt ? nt_insert(self, node, -1) : 0;
1751 rev = PyInt_AsLong(value);
1758 rev = PyInt_AsLong(value);
1752 if (rev > INT_MAX || rev < 0) {
1759 if (rev > INT_MAX || rev < 0) {
1753 if (!PyErr_Occurred())
1760 if (!PyErr_Occurred())
1754 PyErr_SetString(PyExc_ValueError, "rev out of range");
1761 PyErr_SetString(PyExc_ValueError, "rev out of range");
1755 return -1;
1762 return -1;
1756 }
1763 }
1757 return nt_insert(self, node, (int)rev);
1764 return nt_insert(self, node, (int)rev);
1758 }
1765 }
1759
1766
1760 /*
1767 /*
1761 * Find all RevlogNG entries in an index that has inline data. Update
1768 * Find all RevlogNG entries in an index that has inline data. Update
1762 * the optional "offsets" table with those entries.
1769 * the optional "offsets" table with those entries.
1763 */
1770 */
1764 static long inline_scan(indexObject *self, const char **offsets)
1771 static long inline_scan(indexObject *self, const char **offsets)
1765 {
1772 {
1766 const char *data = PyString_AS_STRING(self->data);
1773 const char *data = PyString_AS_STRING(self->data);
1767 Py_ssize_t pos = 0;
1774 Py_ssize_t pos = 0;
1768 Py_ssize_t end = PyString_GET_SIZE(self->data);
1775 Py_ssize_t end = PyString_GET_SIZE(self->data);
1769 long incr = v1_hdrsize;
1776 long incr = v1_hdrsize;
1770 Py_ssize_t len = 0;
1777 Py_ssize_t len = 0;
1771
1778
1772 while (pos + v1_hdrsize <= end && pos >= 0) {
1779 while (pos + v1_hdrsize <= end && pos >= 0) {
1773 uint32_t comp_len;
1780 uint32_t comp_len;
1774 /* 3rd element of header is length of compressed inline data */
1781 /* 3rd element of header is length of compressed inline data */
1775 comp_len = getbe32(data + pos + 8);
1782 comp_len = getbe32(data + pos + 8);
1776 incr = v1_hdrsize + comp_len;
1783 incr = v1_hdrsize + comp_len;
1777 if (offsets)
1784 if (offsets)
1778 offsets[len] = data + pos;
1785 offsets[len] = data + pos;
1779 len++;
1786 len++;
1780 pos += incr;
1787 pos += incr;
1781 }
1788 }
1782
1789
1783 if (pos != end) {
1790 if (pos != end) {
1784 if (!PyErr_Occurred())
1791 if (!PyErr_Occurred())
1785 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1792 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1786 return -1;
1793 return -1;
1787 }
1794 }
1788
1795
1789 return len;
1796 return len;
1790 }
1797 }
1791
1798
1792 static int index_init(indexObject *self, PyObject *args)
1799 static int index_init(indexObject *self, PyObject *args)
1793 {
1800 {
1794 PyObject *data_obj, *inlined_obj;
1801 PyObject *data_obj, *inlined_obj;
1795 Py_ssize_t size;
1802 Py_ssize_t size;
1796
1803
1797 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1804 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1798 self->raw_length = 0;
1805 self->raw_length = 0;
1799 self->added = NULL;
1806 self->added = NULL;
1800 self->cache = NULL;
1807 self->cache = NULL;
1801 self->data = NULL;
1808 self->data = NULL;
1802 self->headrevs = NULL;
1809 self->headrevs = NULL;
1803 self->nt = NULL;
1810 self->nt = NULL;
1804 self->offsets = NULL;
1811 self->offsets = NULL;
1805
1812
1806 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1813 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1807 return -1;
1814 return -1;
1808 if (!PyString_Check(data_obj)) {
1815 if (!PyString_Check(data_obj)) {
1809 PyErr_SetString(PyExc_TypeError, "data is not a string");
1816 PyErr_SetString(PyExc_TypeError, "data is not a string");
1810 return -1;
1817 return -1;
1811 }
1818 }
1812 size = PyString_GET_SIZE(data_obj);
1819 size = PyString_GET_SIZE(data_obj);
1813
1820
1814 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1821 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1815 self->data = data_obj;
1822 self->data = data_obj;
1816
1823
1817 self->ntlength = self->ntcapacity = 0;
1824 self->ntlength = self->ntcapacity = 0;
1818 self->ntdepth = self->ntsplits = 0;
1825 self->ntdepth = self->ntsplits = 0;
1819 self->ntlookups = self->ntmisses = 0;
1826 self->ntlookups = self->ntmisses = 0;
1820 self->ntrev = -1;
1827 self->ntrev = -1;
1821 Py_INCREF(self->data);
1828 Py_INCREF(self->data);
1822
1829
1823 if (self->inlined) {
1830 if (self->inlined) {
1824 long len = inline_scan(self, NULL);
1831 long len = inline_scan(self, NULL);
1825 if (len == -1)
1832 if (len == -1)
1826 goto bail;
1833 goto bail;
1827 self->raw_length = len;
1834 self->raw_length = len;
1828 self->length = len + 1;
1835 self->length = len + 1;
1829 } else {
1836 } else {
1830 if (size % v1_hdrsize) {
1837 if (size % v1_hdrsize) {
1831 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1838 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1832 goto bail;
1839 goto bail;
1833 }
1840 }
1834 self->raw_length = size / v1_hdrsize;
1841 self->raw_length = size / v1_hdrsize;
1835 self->length = self->raw_length + 1;
1842 self->length = self->raw_length + 1;
1836 }
1843 }
1837
1844
1838 return 0;
1845 return 0;
1839 bail:
1846 bail:
1840 return -1;
1847 return -1;
1841 }
1848 }
1842
1849
1843 static PyObject *index_nodemap(indexObject *self)
1850 static PyObject *index_nodemap(indexObject *self)
1844 {
1851 {
1845 Py_INCREF(self);
1852 Py_INCREF(self);
1846 return (PyObject *)self;
1853 return (PyObject *)self;
1847 }
1854 }
1848
1855
1849 static void index_dealloc(indexObject *self)
1856 static void index_dealloc(indexObject *self)
1850 {
1857 {
1851 _index_clearcaches(self);
1858 _index_clearcaches(self);
1852 Py_XDECREF(self->data);
1859 Py_XDECREF(self->data);
1853 Py_XDECREF(self->added);
1860 Py_XDECREF(self->added);
1854 PyObject_Del(self);
1861 PyObject_Del(self);
1855 }
1862 }
1856
1863
1857 static PySequenceMethods index_sequence_methods = {
1864 static PySequenceMethods index_sequence_methods = {
1858 (lenfunc)index_length, /* sq_length */
1865 (lenfunc)index_length, /* sq_length */
1859 0, /* sq_concat */
1866 0, /* sq_concat */
1860 0, /* sq_repeat */
1867 0, /* sq_repeat */
1861 (ssizeargfunc)index_get, /* sq_item */
1868 (ssizeargfunc)index_get, /* sq_item */
1862 0, /* sq_slice */
1869 0, /* sq_slice */
1863 0, /* sq_ass_item */
1870 0, /* sq_ass_item */
1864 0, /* sq_ass_slice */
1871 0, /* sq_ass_slice */
1865 (objobjproc)index_contains, /* sq_contains */
1872 (objobjproc)index_contains, /* sq_contains */
1866 };
1873 };
1867
1874
1868 static PyMappingMethods index_mapping_methods = {
1875 static PyMappingMethods index_mapping_methods = {
1869 (lenfunc)index_length, /* mp_length */
1876 (lenfunc)index_length, /* mp_length */
1870 (binaryfunc)index_getitem, /* mp_subscript */
1877 (binaryfunc)index_getitem, /* mp_subscript */
1871 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1878 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1872 };
1879 };
1873
1880
1874 static PyMethodDef index_methods[] = {
1881 static PyMethodDef index_methods[] = {
1875 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1882 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1876 "return the gca set of the given revs"},
1883 "return the gca set of the given revs"},
1877 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1884 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1878 METH_VARARGS,
1885 METH_VARARGS,
1879 "return the heads of the common ancestors of the given revs"},
1886 "return the heads of the common ancestors of the given revs"},
1880 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1887 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1881 "clear the index caches"},
1888 "clear the index caches"},
1882 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1889 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1883 "get an index entry"},
1890 "get an index entry"},
1884 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1891 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1885 "get head revisions"},
1892 "get head revisions"},
1886 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1893 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1887 "insert an index entry"},
1894 "insert an index entry"},
1888 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1895 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1889 "match a potentially ambiguous node ID"},
1896 "match a potentially ambiguous node ID"},
1890 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1897 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1891 "stats for the index"},
1898 "stats for the index"},
1892 {NULL} /* Sentinel */
1899 {NULL} /* Sentinel */
1893 };
1900 };
1894
1901
1895 static PyGetSetDef index_getset[] = {
1902 static PyGetSetDef index_getset[] = {
1896 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1903 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1897 {NULL} /* Sentinel */
1904 {NULL} /* Sentinel */
1898 };
1905 };
1899
1906
1900 static PyTypeObject indexType = {
1907 static PyTypeObject indexType = {
1901 PyObject_HEAD_INIT(NULL)
1908 PyObject_HEAD_INIT(NULL)
1902 0, /* ob_size */
1909 0, /* ob_size */
1903 "parsers.index", /* tp_name */
1910 "parsers.index", /* tp_name */
1904 sizeof(indexObject), /* tp_basicsize */
1911 sizeof(indexObject), /* tp_basicsize */
1905 0, /* tp_itemsize */
1912 0, /* tp_itemsize */
1906 (destructor)index_dealloc, /* tp_dealloc */
1913 (destructor)index_dealloc, /* tp_dealloc */
1907 0, /* tp_print */
1914 0, /* tp_print */
1908 0, /* tp_getattr */
1915 0, /* tp_getattr */
1909 0, /* tp_setattr */
1916 0, /* tp_setattr */
1910 0, /* tp_compare */
1917 0, /* tp_compare */
1911 0, /* tp_repr */
1918 0, /* tp_repr */
1912 0, /* tp_as_number */
1919 0, /* tp_as_number */
1913 &index_sequence_methods, /* tp_as_sequence */
1920 &index_sequence_methods, /* tp_as_sequence */
1914 &index_mapping_methods, /* tp_as_mapping */
1921 &index_mapping_methods, /* tp_as_mapping */
1915 0, /* tp_hash */
1922 0, /* tp_hash */
1916 0, /* tp_call */
1923 0, /* tp_call */
1917 0, /* tp_str */
1924 0, /* tp_str */
1918 0, /* tp_getattro */
1925 0, /* tp_getattro */
1919 0, /* tp_setattro */
1926 0, /* tp_setattro */
1920 0, /* tp_as_buffer */
1927 0, /* tp_as_buffer */
1921 Py_TPFLAGS_DEFAULT, /* tp_flags */
1928 Py_TPFLAGS_DEFAULT, /* tp_flags */
1922 "revlog index", /* tp_doc */
1929 "revlog index", /* tp_doc */
1923 0, /* tp_traverse */
1930 0, /* tp_traverse */
1924 0, /* tp_clear */
1931 0, /* tp_clear */
1925 0, /* tp_richcompare */
1932 0, /* tp_richcompare */
1926 0, /* tp_weaklistoffset */
1933 0, /* tp_weaklistoffset */
1927 0, /* tp_iter */
1934 0, /* tp_iter */
1928 0, /* tp_iternext */
1935 0, /* tp_iternext */
1929 index_methods, /* tp_methods */
1936 index_methods, /* tp_methods */
1930 0, /* tp_members */
1937 0, /* tp_members */
1931 index_getset, /* tp_getset */
1938 index_getset, /* tp_getset */
1932 0, /* tp_base */
1939 0, /* tp_base */
1933 0, /* tp_dict */
1940 0, /* tp_dict */
1934 0, /* tp_descr_get */
1941 0, /* tp_descr_get */
1935 0, /* tp_descr_set */
1942 0, /* tp_descr_set */
1936 0, /* tp_dictoffset */
1943 0, /* tp_dictoffset */
1937 (initproc)index_init, /* tp_init */
1944 (initproc)index_init, /* tp_init */
1938 0, /* tp_alloc */
1945 0, /* tp_alloc */
1939 };
1946 };
1940
1947
1941 /*
1948 /*
1942 * returns a tuple of the form (index, index, cache) with elements as
1949 * returns a tuple of the form (index, index, cache) with elements as
1943 * follows:
1950 * follows:
1944 *
1951 *
1945 * index: an index object that lazily parses RevlogNG records
1952 * index: an index object that lazily parses RevlogNG records
1946 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1953 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1947 *
1954 *
1948 * added complications are for backwards compatibility
1955 * added complications are for backwards compatibility
1949 */
1956 */
1950 static PyObject *parse_index2(PyObject *self, PyObject *args)
1957 static PyObject *parse_index2(PyObject *self, PyObject *args)
1951 {
1958 {
1952 PyObject *tuple = NULL, *cache = NULL;
1959 PyObject *tuple = NULL, *cache = NULL;
1953 indexObject *idx;
1960 indexObject *idx;
1954 int ret;
1961 int ret;
1955
1962
1956 idx = PyObject_New(indexObject, &indexType);
1963 idx = PyObject_New(indexObject, &indexType);
1957 if (idx == NULL)
1964 if (idx == NULL)
1958 goto bail;
1965 goto bail;
1959
1966
1960 ret = index_init(idx, args);
1967 ret = index_init(idx, args);
1961 if (ret == -1)
1968 if (ret == -1)
1962 goto bail;
1969 goto bail;
1963
1970
1964 if (idx->inlined) {
1971 if (idx->inlined) {
1965 cache = Py_BuildValue("iO", 0, idx->data);
1972 cache = Py_BuildValue("iO", 0, idx->data);
1966 if (cache == NULL)
1973 if (cache == NULL)
1967 goto bail;
1974 goto bail;
1968 } else {
1975 } else {
1969 cache = Py_None;
1976 cache = Py_None;
1970 Py_INCREF(cache);
1977 Py_INCREF(cache);
1971 }
1978 }
1972
1979
1973 tuple = Py_BuildValue("NN", idx, cache);
1980 tuple = Py_BuildValue("NN", idx, cache);
1974 if (!tuple)
1981 if (!tuple)
1975 goto bail;
1982 goto bail;
1976 return tuple;
1983 return tuple;
1977
1984
1978 bail:
1985 bail:
1979 Py_XDECREF(idx);
1986 Py_XDECREF(idx);
1980 Py_XDECREF(cache);
1987 Py_XDECREF(cache);
1981 Py_XDECREF(tuple);
1988 Py_XDECREF(tuple);
1982 return NULL;
1989 return NULL;
1983 }
1990 }
1984
1991
1985 static char parsers_doc[] = "Efficient content parsing.";
1992 static char parsers_doc[] = "Efficient content parsing.";
1986
1993
1987 PyObject *encodedir(PyObject *self, PyObject *args);
1994 PyObject *encodedir(PyObject *self, PyObject *args);
1988 PyObject *pathencode(PyObject *self, PyObject *args);
1995 PyObject *pathencode(PyObject *self, PyObject *args);
1989 PyObject *lowerencode(PyObject *self, PyObject *args);
1996 PyObject *lowerencode(PyObject *self, PyObject *args);
1990
1997
1991 static PyMethodDef methods[] = {
1998 static PyMethodDef methods[] = {
1992 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1999 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1993 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2000 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1994 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2001 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1995 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2002 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
1996 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2003 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1997 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2004 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1998 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2005 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1999 {NULL, NULL}
2006 {NULL, NULL}
2000 };
2007 };
2001
2008
2002 void dirs_module_init(PyObject *mod);
2009 void dirs_module_init(PyObject *mod);
2003
2010
2004 static void module_init(PyObject *mod)
2011 static void module_init(PyObject *mod)
2005 {
2012 {
2006 /* This module constant has two purposes. First, it lets us unit test
2013 /* This module constant has two purposes. First, it lets us unit test
2007 * the ImportError raised without hard-coding any error text. This
2014 * the ImportError raised without hard-coding any error text. This
2008 * means we can change the text in the future without breaking tests,
2015 * means we can change the text in the future without breaking tests,
2009 * even across changesets without a recompile. Second, its presence
2016 * even across changesets without a recompile. Second, its presence
2010 * can be used to determine whether the version-checking logic is
2017 * can be used to determine whether the version-checking logic is
2011 * present, which also helps in testing across changesets without a
2018 * present, which also helps in testing across changesets without a
2012 * recompile. Note that this means the pure-Python version of parsers
2019 * recompile. Note that this means the pure-Python version of parsers
2013 * should not have this module constant. */
2020 * should not have this module constant. */
2014 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2021 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2015
2022
2016 dirs_module_init(mod);
2023 dirs_module_init(mod);
2017
2024
2018 indexType.tp_new = PyType_GenericNew;
2025 indexType.tp_new = PyType_GenericNew;
2019 if (PyType_Ready(&indexType) < 0)
2026 if (PyType_Ready(&indexType) < 0)
2020 return;
2027 return;
2021 Py_INCREF(&indexType);
2028 Py_INCREF(&indexType);
2022
2029
2023 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2030 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2024
2031
2025 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2032 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2026 -1, -1, -1, -1, nullid, 20);
2033 -1, -1, -1, -1, nullid, 20);
2027 if (nullentry)
2034 if (nullentry)
2028 PyObject_GC_UnTrack(nullentry);
2035 PyObject_GC_UnTrack(nullentry);
2029
2036
2030 dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1);
2037 dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1);
2031 }
2038 }
2032
2039
2033 static int check_python_version(void)
2040 static int check_python_version(void)
2034 {
2041 {
2035 PyObject *sys = PyImport_ImportModule("sys");
2042 PyObject *sys = PyImport_ImportModule("sys");
2036 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2043 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2037 /* sys.hexversion is a 32-bit number by default, so the -1 case
2044 /* sys.hexversion is a 32-bit number by default, so the -1 case
2038 * should only occur in unusual circumstances (e.g. if sys.hexversion
2045 * should only occur in unusual circumstances (e.g. if sys.hexversion
2039 * is manually set to an invalid value). */
2046 * is manually set to an invalid value). */
2040 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2047 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2041 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2048 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2042 "modules were compiled with Python " PY_VERSION ", but "
2049 "modules were compiled with Python " PY_VERSION ", but "
2043 "Mercurial is currently using Python with sys.hexversion=%ld: "
2050 "Mercurial is currently using Python with sys.hexversion=%ld: "
2044 "Python %s\n at: %s", versionerrortext, hexversion,
2051 "Python %s\n at: %s", versionerrortext, hexversion,
2045 Py_GetVersion(), Py_GetProgramFullPath());
2052 Py_GetVersion(), Py_GetProgramFullPath());
2046 return -1;
2053 return -1;
2047 }
2054 }
2048 return 0;
2055 return 0;
2049 }
2056 }
2050
2057
2051 #ifdef IS_PY3K
2058 #ifdef IS_PY3K
2052 static struct PyModuleDef parsers_module = {
2059 static struct PyModuleDef parsers_module = {
2053 PyModuleDef_HEAD_INIT,
2060 PyModuleDef_HEAD_INIT,
2054 "parsers",
2061 "parsers",
2055 parsers_doc,
2062 parsers_doc,
2056 -1,
2063 -1,
2057 methods
2064 methods
2058 };
2065 };
2059
2066
2060 PyMODINIT_FUNC PyInit_parsers(void)
2067 PyMODINIT_FUNC PyInit_parsers(void)
2061 {
2068 {
2062 PyObject *mod;
2069 PyObject *mod;
2063
2070
2064 if (check_python_version() == -1)
2071 if (check_python_version() == -1)
2065 return;
2072 return;
2066 mod = PyModule_Create(&parsers_module);
2073 mod = PyModule_Create(&parsers_module);
2067 module_init(mod);
2074 module_init(mod);
2068 return mod;
2075 return mod;
2069 }
2076 }
2070 #else
2077 #else
2071 PyMODINIT_FUNC initparsers(void)
2078 PyMODINIT_FUNC initparsers(void)
2072 {
2079 {
2073 PyObject *mod;
2080 PyObject *mod;
2074
2081
2075 if (check_python_version() == -1)
2082 if (check_python_version() == -1)
2076 return;
2083 return;
2077 mod = Py_InitModule3("parsers", methods, parsers_doc);
2084 mod = Py_InitModule3("parsers", methods, parsers_doc);
2078 module_init(mod);
2085 module_init(mod);
2079 }
2086 }
2080 #endif
2087 #endif
General Comments 0
You need to be logged in to leave comments. Login now