##// END OF EJS Templates
parsers: cache the result of index_headrevs...
Bryan O'Sullivan -
r16787:bda96ce9 default
parent child Browse files
Show More
@@ -1,1368 +1,1399 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 <string.h>
12 #include <string.h>
13
13
14 #include "util.h"
14 #include "util.h"
15
15
16 static inline int hexdigit(const char *p, Py_ssize_t off)
16 static inline int hexdigit(const char *p, Py_ssize_t off)
17 {
17 {
18 char c = p[off];
18 char c = p[off];
19
19
20 if (c >= '0' && c <= '9')
20 if (c >= '0' && c <= '9')
21 return c - '0';
21 return c - '0';
22 if (c >= 'a' && c <= 'f')
22 if (c >= 'a' && c <= 'f')
23 return c - 'a' + 10;
23 return c - 'a' + 10;
24 if (c >= 'A' && c <= 'F')
24 if (c >= 'A' && c <= 'F')
25 return c - 'A' + 10;
25 return c - 'A' + 10;
26
26
27 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
27 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
28 return 0;
28 return 0;
29 }
29 }
30
30
31 /*
31 /*
32 * Turn a hex-encoded string into binary.
32 * Turn a hex-encoded string into binary.
33 */
33 */
34 static PyObject *unhexlify(const char *str, int len)
34 static PyObject *unhexlify(const char *str, int len)
35 {
35 {
36 PyObject *ret;
36 PyObject *ret;
37 char *d;
37 char *d;
38 int i;
38 int i;
39
39
40 ret = PyBytes_FromStringAndSize(NULL, len / 2);
40 ret = PyBytes_FromStringAndSize(NULL, len / 2);
41
41
42 if (!ret)
42 if (!ret)
43 return NULL;
43 return NULL;
44
44
45 d = PyBytes_AsString(ret);
45 d = PyBytes_AsString(ret);
46
46
47 for (i = 0; i < len;) {
47 for (i = 0; i < len;) {
48 int hi = hexdigit(str, i++);
48 int hi = hexdigit(str, i++);
49 int lo = hexdigit(str, i++);
49 int lo = hexdigit(str, i++);
50 *d++ = (hi << 4) | lo;
50 *d++ = (hi << 4) | lo;
51 }
51 }
52
52
53 return ret;
53 return ret;
54 }
54 }
55
55
56 /*
56 /*
57 * This code assumes that a manifest is stitched together with newline
57 * This code assumes that a manifest is stitched together with newline
58 * ('\n') characters.
58 * ('\n') characters.
59 */
59 */
60 static PyObject *parse_manifest(PyObject *self, PyObject *args)
60 static PyObject *parse_manifest(PyObject *self, PyObject *args)
61 {
61 {
62 PyObject *mfdict, *fdict;
62 PyObject *mfdict, *fdict;
63 char *str, *cur, *start, *zero;
63 char *str, *cur, *start, *zero;
64 int len;
64 int len;
65
65
66 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
66 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
67 &PyDict_Type, &mfdict,
67 &PyDict_Type, &mfdict,
68 &PyDict_Type, &fdict,
68 &PyDict_Type, &fdict,
69 &str, &len))
69 &str, &len))
70 goto quit;
70 goto quit;
71
71
72 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
72 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
73 PyObject *file = NULL, *node = NULL;
73 PyObject *file = NULL, *node = NULL;
74 PyObject *flags = NULL;
74 PyObject *flags = NULL;
75 int nlen;
75 int nlen;
76
76
77 if (!*cur) {
77 if (!*cur) {
78 zero = cur;
78 zero = cur;
79 continue;
79 continue;
80 }
80 }
81 else if (*cur != '\n')
81 else if (*cur != '\n')
82 continue;
82 continue;
83
83
84 if (!zero) {
84 if (!zero) {
85 PyErr_SetString(PyExc_ValueError,
85 PyErr_SetString(PyExc_ValueError,
86 "manifest entry has no separator");
86 "manifest entry has no separator");
87 goto quit;
87 goto quit;
88 }
88 }
89
89
90 file = PyBytes_FromStringAndSize(start, zero - start);
90 file = PyBytes_FromStringAndSize(start, zero - start);
91
91
92 if (!file)
92 if (!file)
93 goto bail;
93 goto bail;
94
94
95 nlen = cur - zero - 1;
95 nlen = cur - zero - 1;
96
96
97 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
97 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
98 if (!node)
98 if (!node)
99 goto bail;
99 goto bail;
100
100
101 if (nlen > 40) {
101 if (nlen > 40) {
102 flags = PyBytes_FromStringAndSize(zero + 41,
102 flags = PyBytes_FromStringAndSize(zero + 41,
103 nlen - 40);
103 nlen - 40);
104 if (!flags)
104 if (!flags)
105 goto bail;
105 goto bail;
106
106
107 if (PyDict_SetItem(fdict, file, flags) == -1)
107 if (PyDict_SetItem(fdict, file, flags) == -1)
108 goto bail;
108 goto bail;
109 }
109 }
110
110
111 if (PyDict_SetItem(mfdict, file, node) == -1)
111 if (PyDict_SetItem(mfdict, file, node) == -1)
112 goto bail;
112 goto bail;
113
113
114 start = cur + 1;
114 start = cur + 1;
115 zero = NULL;
115 zero = NULL;
116
116
117 Py_XDECREF(flags);
117 Py_XDECREF(flags);
118 Py_XDECREF(node);
118 Py_XDECREF(node);
119 Py_XDECREF(file);
119 Py_XDECREF(file);
120 continue;
120 continue;
121 bail:
121 bail:
122 Py_XDECREF(flags);
122 Py_XDECREF(flags);
123 Py_XDECREF(node);
123 Py_XDECREF(node);
124 Py_XDECREF(file);
124 Py_XDECREF(file);
125 goto quit;
125 goto quit;
126 }
126 }
127
127
128 if (len > 0 && *(cur - 1) != '\n') {
128 if (len > 0 && *(cur - 1) != '\n') {
129 PyErr_SetString(PyExc_ValueError,
129 PyErr_SetString(PyExc_ValueError,
130 "manifest contains trailing garbage");
130 "manifest contains trailing garbage");
131 goto quit;
131 goto quit;
132 }
132 }
133
133
134 Py_INCREF(Py_None);
134 Py_INCREF(Py_None);
135 return Py_None;
135 return Py_None;
136 quit:
136 quit:
137 return NULL;
137 return NULL;
138 }
138 }
139
139
140 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
140 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
141 {
141 {
142 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
142 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
143 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
143 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
144 char *str, *cur, *end, *cpos;
144 char *str, *cur, *end, *cpos;
145 int state, mode, size, mtime;
145 int state, mode, size, mtime;
146 unsigned int flen;
146 unsigned int flen;
147 int len;
147 int len;
148
148
149 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
149 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
150 &PyDict_Type, &dmap,
150 &PyDict_Type, &dmap,
151 &PyDict_Type, &cmap,
151 &PyDict_Type, &cmap,
152 &str, &len))
152 &str, &len))
153 goto quit;
153 goto quit;
154
154
155 /* read parents */
155 /* read parents */
156 if (len < 40)
156 if (len < 40)
157 goto quit;
157 goto quit;
158
158
159 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
159 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
160 if (!parents)
160 if (!parents)
161 goto quit;
161 goto quit;
162
162
163 /* read filenames */
163 /* read filenames */
164 cur = str + 40;
164 cur = str + 40;
165 end = str + len;
165 end = str + len;
166
166
167 while (cur < end - 17) {
167 while (cur < end - 17) {
168 /* unpack header */
168 /* unpack header */
169 state = *cur;
169 state = *cur;
170 mode = getbe32(cur + 1);
170 mode = getbe32(cur + 1);
171 size = getbe32(cur + 5);
171 size = getbe32(cur + 5);
172 mtime = getbe32(cur + 9);
172 mtime = getbe32(cur + 9);
173 flen = getbe32(cur + 13);
173 flen = getbe32(cur + 13);
174 cur += 17;
174 cur += 17;
175 if (cur + flen > end || cur + flen < cur) {
175 if (cur + flen > end || cur + flen < cur) {
176 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
176 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
177 goto quit;
177 goto quit;
178 }
178 }
179
179
180 entry = Py_BuildValue("ciii", state, mode, size, mtime);
180 entry = Py_BuildValue("ciii", state, mode, size, mtime);
181 if (!entry)
181 if (!entry)
182 goto quit;
182 goto quit;
183 PyObject_GC_UnTrack(entry); /* don't waste time with this */
183 PyObject_GC_UnTrack(entry); /* don't waste time with this */
184
184
185 cpos = memchr(cur, 0, flen);
185 cpos = memchr(cur, 0, flen);
186 if (cpos) {
186 if (cpos) {
187 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
187 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
188 cname = PyBytes_FromStringAndSize(cpos + 1,
188 cname = PyBytes_FromStringAndSize(cpos + 1,
189 flen - (cpos - cur) - 1);
189 flen - (cpos - cur) - 1);
190 if (!fname || !cname ||
190 if (!fname || !cname ||
191 PyDict_SetItem(cmap, fname, cname) == -1 ||
191 PyDict_SetItem(cmap, fname, cname) == -1 ||
192 PyDict_SetItem(dmap, fname, entry) == -1)
192 PyDict_SetItem(dmap, fname, entry) == -1)
193 goto quit;
193 goto quit;
194 Py_DECREF(cname);
194 Py_DECREF(cname);
195 } else {
195 } else {
196 fname = PyBytes_FromStringAndSize(cur, flen);
196 fname = PyBytes_FromStringAndSize(cur, flen);
197 if (!fname ||
197 if (!fname ||
198 PyDict_SetItem(dmap, fname, entry) == -1)
198 PyDict_SetItem(dmap, fname, entry) == -1)
199 goto quit;
199 goto quit;
200 }
200 }
201 cur += flen;
201 cur += flen;
202 Py_DECREF(fname);
202 Py_DECREF(fname);
203 Py_DECREF(entry);
203 Py_DECREF(entry);
204 fname = cname = entry = NULL;
204 fname = cname = entry = NULL;
205 }
205 }
206
206
207 ret = parents;
207 ret = parents;
208 Py_INCREF(ret);
208 Py_INCREF(ret);
209 quit:
209 quit:
210 Py_XDECREF(fname);
210 Py_XDECREF(fname);
211 Py_XDECREF(cname);
211 Py_XDECREF(cname);
212 Py_XDECREF(entry);
212 Py_XDECREF(entry);
213 Py_XDECREF(parents);
213 Py_XDECREF(parents);
214 return ret;
214 return ret;
215 }
215 }
216
216
217 /*
217 /*
218 * A base-16 trie for fast node->rev mapping.
218 * A base-16 trie for fast node->rev mapping.
219 *
219 *
220 * Positive value is index of the next node in the trie
220 * Positive value is index of the next node in the trie
221 * Negative value is a leaf: -(rev + 1)
221 * Negative value is a leaf: -(rev + 1)
222 * Zero is empty
222 * Zero is empty
223 */
223 */
224 typedef struct {
224 typedef struct {
225 int children[16];
225 int children[16];
226 } nodetree;
226 } nodetree;
227
227
228 /*
228 /*
229 * This class has two behaviours.
229 * This class has two behaviours.
230 *
230 *
231 * When used in a list-like way (with integer keys), we decode an
231 * When used in a list-like way (with integer keys), we decode an
232 * entry in a RevlogNG index file on demand. Our last entry is a
232 * entry in a RevlogNG index file on demand. Our last entry is a
233 * sentinel, always a nullid. We have limited support for
233 * sentinel, always a nullid. We have limited support for
234 * integer-keyed insert and delete, only at elements right before the
234 * integer-keyed insert and delete, only at elements right before the
235 * sentinel.
235 * sentinel.
236 *
236 *
237 * With string keys, we lazily perform a reverse mapping from node to
237 * With string keys, we lazily perform a reverse mapping from node to
238 * rev, using a base-16 trie.
238 * rev, using a base-16 trie.
239 */
239 */
240 typedef struct {
240 typedef struct {
241 PyObject_HEAD
241 PyObject_HEAD
242 /* Type-specific fields go here. */
242 /* Type-specific fields go here. */
243 PyObject *data; /* raw bytes of index */
243 PyObject *data; /* raw bytes of index */
244 PyObject **cache; /* cached tuples */
244 PyObject **cache; /* cached tuples */
245 const char **offsets; /* populated on demand */
245 const char **offsets; /* populated on demand */
246 Py_ssize_t raw_length; /* original number of elements */
246 Py_ssize_t raw_length; /* original number of elements */
247 Py_ssize_t length; /* current number of elements */
247 Py_ssize_t length; /* current number of elements */
248 PyObject *added; /* populated on demand */
248 PyObject *added; /* populated on demand */
249 PyObject *headrevs; /* cache, invalidated on changes */
249 nodetree *nt; /* base-16 trie */
250 nodetree *nt; /* base-16 trie */
250 int ntlength; /* # nodes in use */
251 int ntlength; /* # nodes in use */
251 int ntcapacity; /* # nodes allocated */
252 int ntcapacity; /* # nodes allocated */
252 int ntdepth; /* maximum depth of tree */
253 int ntdepth; /* maximum depth of tree */
253 int ntsplits; /* # splits performed */
254 int ntsplits; /* # splits performed */
254 int ntrev; /* last rev scanned */
255 int ntrev; /* last rev scanned */
255 int ntlookups; /* # lookups */
256 int ntlookups; /* # lookups */
256 int ntmisses; /* # lookups that miss the cache */
257 int ntmisses; /* # lookups that miss the cache */
257 int inlined;
258 int inlined;
258 } indexObject;
259 } indexObject;
259
260
260 static Py_ssize_t index_length(const indexObject *self)
261 static Py_ssize_t index_length(const indexObject *self)
261 {
262 {
262 if (self->added == NULL)
263 if (self->added == NULL)
263 return self->length;
264 return self->length;
264 return self->length + PyList_GET_SIZE(self->added);
265 return self->length + PyList_GET_SIZE(self->added);
265 }
266 }
266
267
267 static PyObject *nullentry;
268 static PyObject *nullentry;
268 static const char nullid[20];
269 static const char nullid[20];
269
270
270 static long inline_scan(indexObject *self, const char **offsets);
271 static long inline_scan(indexObject *self, const char **offsets);
271
272
272 #if LONG_MAX == 0x7fffffffL
273 #if LONG_MAX == 0x7fffffffL
273 static char *tuple_format = "Kiiiiiis#";
274 static char *tuple_format = "Kiiiiiis#";
274 #else
275 #else
275 static char *tuple_format = "kiiiiiis#";
276 static char *tuple_format = "kiiiiiis#";
276 #endif
277 #endif
277
278
278 /*
279 /*
279 * Return a pointer to the beginning of a RevlogNG record.
280 * Return a pointer to the beginning of a RevlogNG record.
280 */
281 */
281 static const char *index_deref(indexObject *self, Py_ssize_t pos)
282 static const char *index_deref(indexObject *self, Py_ssize_t pos)
282 {
283 {
283 if (self->inlined && pos > 0) {
284 if (self->inlined && pos > 0) {
284 if (self->offsets == NULL) {
285 if (self->offsets == NULL) {
285 self->offsets = malloc(self->raw_length *
286 self->offsets = malloc(self->raw_length *
286 sizeof(*self->offsets));
287 sizeof(*self->offsets));
287 if (self->offsets == NULL)
288 if (self->offsets == NULL)
288 return (const char *)PyErr_NoMemory();
289 return (const char *)PyErr_NoMemory();
289 inline_scan(self, self->offsets);
290 inline_scan(self, self->offsets);
290 }
291 }
291 return self->offsets[pos];
292 return self->offsets[pos];
292 }
293 }
293
294
294 return PyString_AS_STRING(self->data) + pos * 64;
295 return PyString_AS_STRING(self->data) + pos * 64;
295 }
296 }
296
297
297 /*
298 /*
298 * RevlogNG format (all in big endian, data may be inlined):
299 * RevlogNG format (all in big endian, data may be inlined):
299 * 6 bytes: offset
300 * 6 bytes: offset
300 * 2 bytes: flags
301 * 2 bytes: flags
301 * 4 bytes: compressed length
302 * 4 bytes: compressed length
302 * 4 bytes: uncompressed length
303 * 4 bytes: uncompressed length
303 * 4 bytes: base revision
304 * 4 bytes: base revision
304 * 4 bytes: link revision
305 * 4 bytes: link revision
305 * 4 bytes: parent 1 revision
306 * 4 bytes: parent 1 revision
306 * 4 bytes: parent 2 revision
307 * 4 bytes: parent 2 revision
307 * 32 bytes: nodeid (only 20 bytes used)
308 * 32 bytes: nodeid (only 20 bytes used)
308 */
309 */
309 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
310 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
310 {
311 {
311 uint64_t offset_flags;
312 uint64_t offset_flags;
312 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
313 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
313 const char *c_node_id;
314 const char *c_node_id;
314 const char *data;
315 const char *data;
315 Py_ssize_t length = index_length(self);
316 Py_ssize_t length = index_length(self);
316 PyObject *entry;
317 PyObject *entry;
317
318
318 if (pos < 0)
319 if (pos < 0)
319 pos += length;
320 pos += length;
320
321
321 if (pos < 0 || pos >= length) {
322 if (pos < 0 || pos >= length) {
322 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
323 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
323 return NULL;
324 return NULL;
324 }
325 }
325
326
326 if (pos == length - 1) {
327 if (pos == length - 1) {
327 Py_INCREF(nullentry);
328 Py_INCREF(nullentry);
328 return nullentry;
329 return nullentry;
329 }
330 }
330
331
331 if (pos >= self->length - 1) {
332 if (pos >= self->length - 1) {
332 PyObject *obj;
333 PyObject *obj;
333 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
334 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
334 Py_INCREF(obj);
335 Py_INCREF(obj);
335 return obj;
336 return obj;
336 }
337 }
337
338
338 if (self->cache) {
339 if (self->cache) {
339 if (self->cache[pos]) {
340 if (self->cache[pos]) {
340 Py_INCREF(self->cache[pos]);
341 Py_INCREF(self->cache[pos]);
341 return self->cache[pos];
342 return self->cache[pos];
342 }
343 }
343 } else {
344 } else {
344 self->cache = calloc(self->raw_length, sizeof(PyObject *));
345 self->cache = calloc(self->raw_length, sizeof(PyObject *));
345 if (self->cache == NULL)
346 if (self->cache == NULL)
346 return PyErr_NoMemory();
347 return PyErr_NoMemory();
347 }
348 }
348
349
349 data = index_deref(self, pos);
350 data = index_deref(self, pos);
350 if (data == NULL)
351 if (data == NULL)
351 return NULL;
352 return NULL;
352
353
353 offset_flags = getbe32(data + 4);
354 offset_flags = getbe32(data + 4);
354 if (pos == 0) /* mask out version number for the first entry */
355 if (pos == 0) /* mask out version number for the first entry */
355 offset_flags &= 0xFFFF;
356 offset_flags &= 0xFFFF;
356 else {
357 else {
357 uint32_t offset_high = getbe32(data);
358 uint32_t offset_high = getbe32(data);
358 offset_flags |= ((uint64_t)offset_high) << 32;
359 offset_flags |= ((uint64_t)offset_high) << 32;
359 }
360 }
360
361
361 comp_len = getbe32(data + 8);
362 comp_len = getbe32(data + 8);
362 uncomp_len = getbe32(data + 12);
363 uncomp_len = getbe32(data + 12);
363 base_rev = getbe32(data + 16);
364 base_rev = getbe32(data + 16);
364 link_rev = getbe32(data + 20);
365 link_rev = getbe32(data + 20);
365 parent_1 = getbe32(data + 24);
366 parent_1 = getbe32(data + 24);
366 parent_2 = getbe32(data + 28);
367 parent_2 = getbe32(data + 28);
367 c_node_id = data + 32;
368 c_node_id = data + 32;
368
369
369 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
370 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
370 uncomp_len, base_rev, link_rev,
371 uncomp_len, base_rev, link_rev,
371 parent_1, parent_2, c_node_id, 20);
372 parent_1, parent_2, c_node_id, 20);
372
373
373 if (entry)
374 if (entry)
374 PyObject_GC_UnTrack(entry);
375 PyObject_GC_UnTrack(entry);
375
376
376 self->cache[pos] = entry;
377 self->cache[pos] = entry;
377 Py_INCREF(entry);
378 Py_INCREF(entry);
378
379
379 return entry;
380 return entry;
380 }
381 }
381
382
382 /*
383 /*
383 * Return the 20-byte SHA of the node corresponding to the given rev.
384 * Return the 20-byte SHA of the node corresponding to the given rev.
384 */
385 */
385 static const char *index_node(indexObject *self, Py_ssize_t pos)
386 static const char *index_node(indexObject *self, Py_ssize_t pos)
386 {
387 {
387 Py_ssize_t length = index_length(self);
388 Py_ssize_t length = index_length(self);
388 const char *data;
389 const char *data;
389
390
390 if (pos == length - 1 || pos == INT_MAX)
391 if (pos == length - 1 || pos == INT_MAX)
391 return nullid;
392 return nullid;
392
393
393 if (pos >= length)
394 if (pos >= length)
394 return NULL;
395 return NULL;
395
396
396 if (pos >= self->length - 1) {
397 if (pos >= self->length - 1) {
397 PyObject *tuple, *str;
398 PyObject *tuple, *str;
398 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
399 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
399 str = PyTuple_GetItem(tuple, 7);
400 str = PyTuple_GetItem(tuple, 7);
400 return str ? PyString_AS_STRING(str) : NULL;
401 return str ? PyString_AS_STRING(str) : NULL;
401 }
402 }
402
403
403 data = index_deref(self, pos);
404 data = index_deref(self, pos);
404 return data ? data + 32 : NULL;
405 return data ? data + 32 : NULL;
405 }
406 }
406
407
407 static int nt_insert(indexObject *self, const char *node, int rev);
408 static int nt_insert(indexObject *self, const char *node, int rev);
408
409
409 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
410 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
410 {
411 {
411 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
412 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
412 return -1;
413 return -1;
413 if (*nodelen == 20)
414 if (*nodelen == 20)
414 return 0;
415 return 0;
415 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
416 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
416 return -1;
417 return -1;
417 }
418 }
418
419
419 static PyObject *index_insert(indexObject *self, PyObject *args)
420 static PyObject *index_insert(indexObject *self, PyObject *args)
420 {
421 {
421 PyObject *obj;
422 PyObject *obj;
422 char *node;
423 char *node;
423 long offset;
424 long offset;
424 Py_ssize_t len, nodelen;
425 Py_ssize_t len, nodelen;
425
426
426 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
427 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
427 return NULL;
428 return NULL;
428
429
429 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
430 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
430 PyErr_SetString(PyExc_TypeError, "8-tuple required");
431 PyErr_SetString(PyExc_TypeError, "8-tuple required");
431 return NULL;
432 return NULL;
432 }
433 }
433
434
434 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
435 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
435 return NULL;
436 return NULL;
436
437
437 len = index_length(self);
438 len = index_length(self);
438
439
439 if (offset < 0)
440 if (offset < 0)
440 offset += len;
441 offset += len;
441
442
442 if (offset != len - 1) {
443 if (offset != len - 1) {
443 PyErr_SetString(PyExc_IndexError,
444 PyErr_SetString(PyExc_IndexError,
444 "insert only supported at index -1");
445 "insert only supported at index -1");
445 return NULL;
446 return NULL;
446 }
447 }
447
448
448 if (offset > INT_MAX) {
449 if (offset > INT_MAX) {
449 PyErr_SetString(PyExc_ValueError,
450 PyErr_SetString(PyExc_ValueError,
450 "currently only 2**31 revs supported");
451 "currently only 2**31 revs supported");
451 return NULL;
452 return NULL;
452 }
453 }
453
454
454 if (self->added == NULL) {
455 if (self->added == NULL) {
455 self->added = PyList_New(0);
456 self->added = PyList_New(0);
456 if (self->added == NULL)
457 if (self->added == NULL)
457 return NULL;
458 return NULL;
458 }
459 }
459
460
460 if (PyList_Append(self->added, obj) == -1)
461 if (PyList_Append(self->added, obj) == -1)
461 return NULL;
462 return NULL;
462
463
463 if (self->nt)
464 if (self->nt)
464 nt_insert(self, node, (int)offset);
465 nt_insert(self, node, (int)offset);
465
466
467 Py_CLEAR(self->headrevs);
466 Py_RETURN_NONE;
468 Py_RETURN_NONE;
467 }
469 }
468
470
469 static void _index_clearcaches(indexObject *self)
471 static void _index_clearcaches(indexObject *self)
470 {
472 {
471 if (self->cache) {
473 if (self->cache) {
472 Py_ssize_t i;
474 Py_ssize_t i;
473
475
474 for (i = 0; i < self->raw_length; i++)
476 for (i = 0; i < self->raw_length; i++)
475 Py_CLEAR(self->cache[i]);
477 Py_CLEAR(self->cache[i]);
476 free(self->cache);
478 free(self->cache);
477 self->cache = NULL;
479 self->cache = NULL;
478 }
480 }
479 if (self->offsets) {
481 if (self->offsets) {
480 free(self->offsets);
482 free(self->offsets);
481 self->offsets = NULL;
483 self->offsets = NULL;
482 }
484 }
483 if (self->nt) {
485 if (self->nt) {
484 free(self->nt);
486 free(self->nt);
485 self->nt = NULL;
487 self->nt = NULL;
486 }
488 }
489 Py_CLEAR(self->headrevs);
487 }
490 }
488
491
489 static PyObject *index_clearcaches(indexObject *self)
492 static PyObject *index_clearcaches(indexObject *self)
490 {
493 {
491 _index_clearcaches(self);
494 _index_clearcaches(self);
492 self->ntlength = self->ntcapacity = 0;
495 self->ntlength = self->ntcapacity = 0;
493 self->ntdepth = self->ntsplits = 0;
496 self->ntdepth = self->ntsplits = 0;
494 self->ntrev = -1;
497 self->ntrev = -1;
495 self->ntlookups = self->ntmisses = 0;
498 self->ntlookups = self->ntmisses = 0;
496 Py_RETURN_NONE;
499 Py_RETURN_NONE;
497 }
500 }
498
501
499 static PyObject *index_stats(indexObject *self)
502 static PyObject *index_stats(indexObject *self)
500 {
503 {
501 PyObject *obj = PyDict_New();
504 PyObject *obj = PyDict_New();
502
505
503 if (obj == NULL)
506 if (obj == NULL)
504 return NULL;
507 return NULL;
505
508
506 #define istat(__n, __d) \
509 #define istat(__n, __d) \
507 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
510 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
508 goto bail;
511 goto bail;
509
512
510 if (self->added) {
513 if (self->added) {
511 Py_ssize_t len = PyList_GET_SIZE(self->added);
514 Py_ssize_t len = PyList_GET_SIZE(self->added);
512 if (PyDict_SetItemString(obj, "index entries added",
515 if (PyDict_SetItemString(obj, "index entries added",
513 PyInt_FromSsize_t(len)) == -1)
516 PyInt_FromSsize_t(len)) == -1)
514 goto bail;
517 goto bail;
515 }
518 }
516
519
517 if (self->raw_length != self->length - 1)
520 if (self->raw_length != self->length - 1)
518 istat(raw_length, "revs on disk");
521 istat(raw_length, "revs on disk");
519 istat(length, "revs in memory");
522 istat(length, "revs in memory");
520 istat(ntcapacity, "node trie capacity");
523 istat(ntcapacity, "node trie capacity");
521 istat(ntdepth, "node trie depth");
524 istat(ntdepth, "node trie depth");
522 istat(ntlength, "node trie count");
525 istat(ntlength, "node trie count");
523 istat(ntlookups, "node trie lookups");
526 istat(ntlookups, "node trie lookups");
524 istat(ntmisses, "node trie misses");
527 istat(ntmisses, "node trie misses");
525 istat(ntrev, "node trie last rev scanned");
528 istat(ntrev, "node trie last rev scanned");
526 istat(ntsplits, "node trie splits");
529 istat(ntsplits, "node trie splits");
527
530
528 #undef istat
531 #undef istat
529
532
530 return obj;
533 return obj;
531
534
532 bail:
535 bail:
533 Py_XDECREF(obj);
536 Py_XDECREF(obj);
534 return NULL;
537 return NULL;
535 }
538 }
536
539
540 /*
541 * When we cache a list, we want to be sure the caller can't mutate
542 * the cached copy.
543 */
544 static PyObject *list_copy(PyObject *list)
545 {
546 Py_ssize_t len = PyList_GET_SIZE(list);
547 PyObject *newlist = PyList_New(len);
548 Py_ssize_t i;
549
550 if (newlist == NULL)
551 return NULL;
552
553 for (i = 0; i < len; i++) {
554 PyObject *obj = PyList_GET_ITEM(list, i);
555 Py_INCREF(obj);
556 PyList_SET_ITEM(newlist, i, obj);
557 }
558
559 return newlist;
560 }
561
537 static PyObject *index_headrevs(indexObject *self)
562 static PyObject *index_headrevs(indexObject *self)
538 {
563 {
539 Py_ssize_t i, len, addlen;
564 Py_ssize_t i, len, addlen;
540 char *nothead = NULL;
565 char *nothead = NULL;
541 PyObject *heads;
566 PyObject *heads;
542
567
568 if (self->headrevs)
569 return list_copy(self->headrevs);
570
543 len = index_length(self) - 1;
571 len = index_length(self) - 1;
544 heads = PyList_New(0);
572 heads = PyList_New(0);
545 if (heads == NULL)
573 if (heads == NULL)
546 goto bail;
574 goto bail;
547 if (len == 0) {
575 if (len == 0) {
548 PyObject *nullid = PyInt_FromLong(-1);
576 PyObject *nullid = PyInt_FromLong(-1);
549 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
577 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
550 Py_XDECREF(nullid);
578 Py_XDECREF(nullid);
551 goto bail;
579 goto bail;
552 }
580 }
553 goto done;
581 goto done;
554 }
582 }
555
583
556 nothead = calloc(len, 1);
584 nothead = calloc(len, 1);
557 if (nothead == NULL)
585 if (nothead == NULL)
558 goto bail;
586 goto bail;
559
587
560 for (i = 0; i < self->raw_length; i++) {
588 for (i = 0; i < self->raw_length; i++) {
561 const char *data = index_deref(self, i);
589 const char *data = index_deref(self, i);
562 int parent_1 = getbe32(data + 24);
590 int parent_1 = getbe32(data + 24);
563 int parent_2 = getbe32(data + 28);
591 int parent_2 = getbe32(data + 28);
564 if (parent_1 >= 0)
592 if (parent_1 >= 0)
565 nothead[parent_1] = 1;
593 nothead[parent_1] = 1;
566 if (parent_2 >= 0)
594 if (parent_2 >= 0)
567 nothead[parent_2] = 1;
595 nothead[parent_2] = 1;
568 }
596 }
569
597
570 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
598 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
571
599
572 for (i = 0; i < addlen; i++) {
600 for (i = 0; i < addlen; i++) {
573 PyObject *rev = PyList_GET_ITEM(self->added, i);
601 PyObject *rev = PyList_GET_ITEM(self->added, i);
574 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
602 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
575 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
603 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
576 long parent_1, parent_2;
604 long parent_1, parent_2;
577
605
578 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
606 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
579 PyErr_SetString(PyExc_TypeError,
607 PyErr_SetString(PyExc_TypeError,
580 "revlog parents are invalid");
608 "revlog parents are invalid");
581 goto bail;
609 goto bail;
582 }
610 }
583 parent_1 = PyInt_AS_LONG(p1);
611 parent_1 = PyInt_AS_LONG(p1);
584 parent_2 = PyInt_AS_LONG(p2);
612 parent_2 = PyInt_AS_LONG(p2);
585 if (parent_1 >= 0)
613 if (parent_1 >= 0)
586 nothead[parent_1] = 1;
614 nothead[parent_1] = 1;
587 if (parent_2 >= 0)
615 if (parent_2 >= 0)
588 nothead[parent_2] = 1;
616 nothead[parent_2] = 1;
589 }
617 }
590
618
591 for (i = 0; i < len; i++) {
619 for (i = 0; i < len; i++) {
592 PyObject *head;
620 PyObject *head;
593
621
594 if (nothead[i])
622 if (nothead[i])
595 continue;
623 continue;
596 head = PyInt_FromLong(i);
624 head = PyInt_FromLong(i);
597 if (head == NULL || PyList_Append(heads, head) == -1) {
625 if (head == NULL || PyList_Append(heads, head) == -1) {
598 Py_XDECREF(head);
626 Py_XDECREF(head);
599 goto bail;
627 goto bail;
600 }
628 }
601 }
629 }
602
630
603 done:
631 done:
632 self->headrevs = heads;
604 free(nothead);
633 free(nothead);
605 return heads;
634 return list_copy(self->headrevs);
606 bail:
635 bail:
607 Py_XDECREF(heads);
636 Py_XDECREF(heads);
608 free(nothead);
637 free(nothead);
609 return NULL;
638 return NULL;
610 }
639 }
611
640
612 static inline int nt_level(const char *node, Py_ssize_t level)
641 static inline int nt_level(const char *node, Py_ssize_t level)
613 {
642 {
614 int v = node[level>>1];
643 int v = node[level>>1];
615 if (!(level & 1))
644 if (!(level & 1))
616 v >>= 4;
645 v >>= 4;
617 return v & 0xf;
646 return v & 0xf;
618 }
647 }
619
648
620 /*
649 /*
621 * Return values:
650 * Return values:
622 *
651 *
623 * -4: match is ambiguous (multiple candidates)
652 * -4: match is ambiguous (multiple candidates)
624 * -2: not found
653 * -2: not found
625 * rest: valid rev
654 * rest: valid rev
626 */
655 */
627 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
656 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
628 int hex)
657 int hex)
629 {
658 {
630 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
659 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
631 int level, maxlevel, off;
660 int level, maxlevel, off;
632
661
633 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
662 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
634 return -1;
663 return -1;
635
664
636 if (self->nt == NULL)
665 if (self->nt == NULL)
637 return -2;
666 return -2;
638
667
639 if (hex)
668 if (hex)
640 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
669 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
641 else
670 else
642 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
671 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
643
672
644 for (level = off = 0; level < maxlevel; level++) {
673 for (level = off = 0; level < maxlevel; level++) {
645 int k = getnybble(node, level);
674 int k = getnybble(node, level);
646 nodetree *n = &self->nt[off];
675 nodetree *n = &self->nt[off];
647 int v = n->children[k];
676 int v = n->children[k];
648
677
649 if (v < 0) {
678 if (v < 0) {
650 const char *n;
679 const char *n;
651 Py_ssize_t i;
680 Py_ssize_t i;
652
681
653 v = -v - 1;
682 v = -v - 1;
654 n = index_node(self, v);
683 n = index_node(self, v);
655 if (n == NULL)
684 if (n == NULL)
656 return -2;
685 return -2;
657 for (i = level; i < maxlevel; i++)
686 for (i = level; i < maxlevel; i++)
658 if (getnybble(node, i) != nt_level(n, i))
687 if (getnybble(node, i) != nt_level(n, i))
659 return -2;
688 return -2;
660 return v;
689 return v;
661 }
690 }
662 if (v == 0)
691 if (v == 0)
663 return -2;
692 return -2;
664 off = v;
693 off = v;
665 }
694 }
666 /* multiple matches against an ambiguous prefix */
695 /* multiple matches against an ambiguous prefix */
667 return -4;
696 return -4;
668 }
697 }
669
698
670 static int nt_new(indexObject *self)
699 static int nt_new(indexObject *self)
671 {
700 {
672 if (self->ntlength == self->ntcapacity) {
701 if (self->ntlength == self->ntcapacity) {
673 self->ntcapacity *= 2;
702 self->ntcapacity *= 2;
674 self->nt = realloc(self->nt,
703 self->nt = realloc(self->nt,
675 self->ntcapacity * sizeof(nodetree));
704 self->ntcapacity * sizeof(nodetree));
676 if (self->nt == NULL) {
705 if (self->nt == NULL) {
677 PyErr_SetString(PyExc_MemoryError, "out of memory");
706 PyErr_SetString(PyExc_MemoryError, "out of memory");
678 return -1;
707 return -1;
679 }
708 }
680 memset(&self->nt[self->ntlength], 0,
709 memset(&self->nt[self->ntlength], 0,
681 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
710 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
682 }
711 }
683 return self->ntlength++;
712 return self->ntlength++;
684 }
713 }
685
714
686 static int nt_insert(indexObject *self, const char *node, int rev)
715 static int nt_insert(indexObject *self, const char *node, int rev)
687 {
716 {
688 int level = 0;
717 int level = 0;
689 int off = 0;
718 int off = 0;
690
719
691 while (level < 40) {
720 while (level < 40) {
692 int k = nt_level(node, level);
721 int k = nt_level(node, level);
693 nodetree *n;
722 nodetree *n;
694 int v;
723 int v;
695
724
696 n = &self->nt[off];
725 n = &self->nt[off];
697 v = n->children[k];
726 v = n->children[k];
698
727
699 if (v == 0) {
728 if (v == 0) {
700 n->children[k] = -rev - 1;
729 n->children[k] = -rev - 1;
701 return 0;
730 return 0;
702 }
731 }
703 if (v < 0) {
732 if (v < 0) {
704 const char *oldnode = index_node(self, -v - 1);
733 const char *oldnode = index_node(self, -v - 1);
705 int noff;
734 int noff;
706
735
707 if (!oldnode || !memcmp(oldnode, node, 20)) {
736 if (!oldnode || !memcmp(oldnode, node, 20)) {
708 n->children[k] = -rev - 1;
737 n->children[k] = -rev - 1;
709 return 0;
738 return 0;
710 }
739 }
711 noff = nt_new(self);
740 noff = nt_new(self);
712 if (noff == -1)
741 if (noff == -1)
713 return -1;
742 return -1;
714 /* self->nt may have been changed by realloc */
743 /* self->nt may have been changed by realloc */
715 self->nt[off].children[k] = noff;
744 self->nt[off].children[k] = noff;
716 off = noff;
745 off = noff;
717 n = &self->nt[off];
746 n = &self->nt[off];
718 n->children[nt_level(oldnode, ++level)] = v;
747 n->children[nt_level(oldnode, ++level)] = v;
719 if (level > self->ntdepth)
748 if (level > self->ntdepth)
720 self->ntdepth = level;
749 self->ntdepth = level;
721 self->ntsplits += 1;
750 self->ntsplits += 1;
722 } else {
751 } else {
723 level += 1;
752 level += 1;
724 off = v;
753 off = v;
725 }
754 }
726 }
755 }
727
756
728 return -1;
757 return -1;
729 }
758 }
730
759
731 static int nt_init(indexObject *self)
760 static int nt_init(indexObject *self)
732 {
761 {
733 if (self->nt == NULL) {
762 if (self->nt == NULL) {
734 self->ntcapacity = self->raw_length < 4
763 self->ntcapacity = self->raw_length < 4
735 ? 4 : self->raw_length / 2;
764 ? 4 : self->raw_length / 2;
736 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
765 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
737 if (self->nt == NULL) {
766 if (self->nt == NULL) {
738 PyErr_NoMemory();
767 PyErr_NoMemory();
739 return -1;
768 return -1;
740 }
769 }
741 self->ntlength = 1;
770 self->ntlength = 1;
742 self->ntrev = (int)index_length(self) - 1;
771 self->ntrev = (int)index_length(self) - 1;
743 self->ntlookups = 1;
772 self->ntlookups = 1;
744 self->ntmisses = 0;
773 self->ntmisses = 0;
745 if (nt_insert(self, nullid, INT_MAX) == -1)
774 if (nt_insert(self, nullid, INT_MAX) == -1)
746 return -1;
775 return -1;
747 }
776 }
748 return 0;
777 return 0;
749 }
778 }
750
779
751 /*
780 /*
752 * Return values:
781 * Return values:
753 *
782 *
754 * -3: error (exception set)
783 * -3: error (exception set)
755 * -2: not found (no exception set)
784 * -2: not found (no exception set)
756 * rest: valid rev
785 * rest: valid rev
757 */
786 */
758 static int index_find_node(indexObject *self,
787 static int index_find_node(indexObject *self,
759 const char *node, Py_ssize_t nodelen)
788 const char *node, Py_ssize_t nodelen)
760 {
789 {
761 int rev;
790 int rev;
762
791
763 self->ntlookups++;
792 self->ntlookups++;
764 rev = nt_find(self, node, nodelen, 0);
793 rev = nt_find(self, node, nodelen, 0);
765 if (rev >= -1)
794 if (rev >= -1)
766 return rev;
795 return rev;
767
796
768 if (nt_init(self) == -1)
797 if (nt_init(self) == -1)
769 return -3;
798 return -3;
770
799
771 /*
800 /*
772 * For the first handful of lookups, we scan the entire index,
801 * For the first handful of lookups, we scan the entire index,
773 * and cache only the matching nodes. This optimizes for cases
802 * and cache only the matching nodes. This optimizes for cases
774 * like "hg tip", where only a few nodes are accessed.
803 * like "hg tip", where only a few nodes are accessed.
775 *
804 *
776 * After that, we cache every node we visit, using a single
805 * After that, we cache every node we visit, using a single
777 * scan amortized over multiple lookups. This gives the best
806 * scan amortized over multiple lookups. This gives the best
778 * bulk performance, e.g. for "hg log".
807 * bulk performance, e.g. for "hg log".
779 */
808 */
780 if (self->ntmisses++ < 4) {
809 if (self->ntmisses++ < 4) {
781 for (rev = self->ntrev - 1; rev >= 0; rev--) {
810 for (rev = self->ntrev - 1; rev >= 0; rev--) {
782 const char *n = index_node(self, rev);
811 const char *n = index_node(self, rev);
783 if (n == NULL)
812 if (n == NULL)
784 return -2;
813 return -2;
785 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
814 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
786 if (nt_insert(self, n, rev) == -1)
815 if (nt_insert(self, n, rev) == -1)
787 return -3;
816 return -3;
788 break;
817 break;
789 }
818 }
790 }
819 }
791 } else {
820 } else {
792 for (rev = self->ntrev - 1; rev >= 0; rev--) {
821 for (rev = self->ntrev - 1; rev >= 0; rev--) {
793 const char *n = index_node(self, rev);
822 const char *n = index_node(self, rev);
794 if (n == NULL) {
823 if (n == NULL) {
795 self->ntrev = rev + 1;
824 self->ntrev = rev + 1;
796 return -2;
825 return -2;
797 }
826 }
798 if (nt_insert(self, n, rev) == -1) {
827 if (nt_insert(self, n, rev) == -1) {
799 self->ntrev = rev + 1;
828 self->ntrev = rev + 1;
800 return -3;
829 return -3;
801 }
830 }
802 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
831 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
803 break;
832 break;
804 }
833 }
805 }
834 }
806 self->ntrev = rev;
835 self->ntrev = rev;
807 }
836 }
808
837
809 if (rev >= 0)
838 if (rev >= 0)
810 return rev;
839 return rev;
811 return -2;
840 return -2;
812 }
841 }
813
842
814 static PyObject *raise_revlog_error(void)
843 static PyObject *raise_revlog_error(void)
815 {
844 {
816 static PyObject *errclass;
845 static PyObject *errclass;
817 PyObject *mod = NULL, *errobj;
846 PyObject *mod = NULL, *errobj;
818
847
819 if (errclass == NULL) {
848 if (errclass == NULL) {
820 PyObject *dict;
849 PyObject *dict;
821
850
822 mod = PyImport_ImportModule("mercurial.error");
851 mod = PyImport_ImportModule("mercurial.error");
823 if (mod == NULL)
852 if (mod == NULL)
824 goto classfail;
853 goto classfail;
825
854
826 dict = PyModule_GetDict(mod);
855 dict = PyModule_GetDict(mod);
827 if (dict == NULL)
856 if (dict == NULL)
828 goto classfail;
857 goto classfail;
829
858
830 errclass = PyDict_GetItemString(dict, "RevlogError");
859 errclass = PyDict_GetItemString(dict, "RevlogError");
831 if (errclass == NULL) {
860 if (errclass == NULL) {
832 PyErr_SetString(PyExc_SystemError,
861 PyErr_SetString(PyExc_SystemError,
833 "could not find RevlogError");
862 "could not find RevlogError");
834 goto classfail;
863 goto classfail;
835 }
864 }
836 Py_INCREF(errclass);
865 Py_INCREF(errclass);
837 }
866 }
838
867
839 errobj = PyObject_CallFunction(errclass, NULL);
868 errobj = PyObject_CallFunction(errclass, NULL);
840 if (errobj == NULL)
869 if (errobj == NULL)
841 return NULL;
870 return NULL;
842 PyErr_SetObject(errclass, errobj);
871 PyErr_SetObject(errclass, errobj);
843 return errobj;
872 return errobj;
844
873
845 classfail:
874 classfail:
846 Py_XDECREF(mod);
875 Py_XDECREF(mod);
847 return NULL;
876 return NULL;
848 }
877 }
849
878
850 static PyObject *index_getitem(indexObject *self, PyObject *value)
879 static PyObject *index_getitem(indexObject *self, PyObject *value)
851 {
880 {
852 char *node;
881 char *node;
853 Py_ssize_t nodelen;
882 Py_ssize_t nodelen;
854 int rev;
883 int rev;
855
884
856 if (PyInt_Check(value))
885 if (PyInt_Check(value))
857 return index_get(self, PyInt_AS_LONG(value));
886 return index_get(self, PyInt_AS_LONG(value));
858
887
859 if (node_check(value, &node, &nodelen) == -1)
888 if (node_check(value, &node, &nodelen) == -1)
860 return NULL;
889 return NULL;
861 rev = index_find_node(self, node, nodelen);
890 rev = index_find_node(self, node, nodelen);
862 if (rev >= -1)
891 if (rev >= -1)
863 return PyInt_FromLong(rev);
892 return PyInt_FromLong(rev);
864 if (rev == -2)
893 if (rev == -2)
865 raise_revlog_error();
894 raise_revlog_error();
866 return NULL;
895 return NULL;
867 }
896 }
868
897
869 static int nt_partialmatch(indexObject *self, const char *node,
898 static int nt_partialmatch(indexObject *self, const char *node,
870 Py_ssize_t nodelen)
899 Py_ssize_t nodelen)
871 {
900 {
872 int rev;
901 int rev;
873
902
874 if (nt_init(self) == -1)
903 if (nt_init(self) == -1)
875 return -3;
904 return -3;
876
905
877 if (self->ntrev > 0) {
906 if (self->ntrev > 0) {
878 /* ensure that the radix tree is fully populated */
907 /* ensure that the radix tree is fully populated */
879 for (rev = self->ntrev - 1; rev >= 0; rev--) {
908 for (rev = self->ntrev - 1; rev >= 0; rev--) {
880 const char *n = index_node(self, rev);
909 const char *n = index_node(self, rev);
881 if (n == NULL)
910 if (n == NULL)
882 return -2;
911 return -2;
883 if (nt_insert(self, n, rev) == -1)
912 if (nt_insert(self, n, rev) == -1)
884 return -3;
913 return -3;
885 }
914 }
886 self->ntrev = rev;
915 self->ntrev = rev;
887 }
916 }
888
917
889 return nt_find(self, node, nodelen, 1);
918 return nt_find(self, node, nodelen, 1);
890 }
919 }
891
920
892 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
921 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
893 {
922 {
894 const char *fullnode;
923 const char *fullnode;
895 int nodelen;
924 int nodelen;
896 char *node;
925 char *node;
897 int rev, i;
926 int rev, i;
898
927
899 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
928 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
900 return NULL;
929 return NULL;
901
930
902 if (nodelen < 4) {
931 if (nodelen < 4) {
903 PyErr_SetString(PyExc_ValueError, "key too short");
932 PyErr_SetString(PyExc_ValueError, "key too short");
904 return NULL;
933 return NULL;
905 }
934 }
906
935
907 if (nodelen > 40)
936 if (nodelen > 40)
908 nodelen = 40;
937 nodelen = 40;
909
938
910 for (i = 0; i < nodelen; i++)
939 for (i = 0; i < nodelen; i++)
911 hexdigit(node, i);
940 hexdigit(node, i);
912 if (PyErr_Occurred()) {
941 if (PyErr_Occurred()) {
913 /* input contains non-hex characters */
942 /* input contains non-hex characters */
914 PyErr_Clear();
943 PyErr_Clear();
915 Py_RETURN_NONE;
944 Py_RETURN_NONE;
916 }
945 }
917
946
918 rev = nt_partialmatch(self, node, nodelen);
947 rev = nt_partialmatch(self, node, nodelen);
919
948
920 switch (rev) {
949 switch (rev) {
921 case -4:
950 case -4:
922 raise_revlog_error();
951 raise_revlog_error();
923 case -3:
952 case -3:
924 return NULL;
953 return NULL;
925 case -2:
954 case -2:
926 Py_RETURN_NONE;
955 Py_RETURN_NONE;
927 case -1:
956 case -1:
928 return PyString_FromStringAndSize(nullid, 20);
957 return PyString_FromStringAndSize(nullid, 20);
929 }
958 }
930
959
931 fullnode = index_node(self, rev);
960 fullnode = index_node(self, rev);
932 if (fullnode == NULL) {
961 if (fullnode == NULL) {
933 PyErr_Format(PyExc_IndexError,
962 PyErr_Format(PyExc_IndexError,
934 "could not access rev %d", rev);
963 "could not access rev %d", rev);
935 return NULL;
964 return NULL;
936 }
965 }
937 return PyString_FromStringAndSize(fullnode, 20);
966 return PyString_FromStringAndSize(fullnode, 20);
938 }
967 }
939
968
940 static PyObject *index_m_get(indexObject *self, PyObject *args)
969 static PyObject *index_m_get(indexObject *self, PyObject *args)
941 {
970 {
942 Py_ssize_t nodelen;
971 Py_ssize_t nodelen;
943 PyObject *val;
972 PyObject *val;
944 char *node;
973 char *node;
945 int rev;
974 int rev;
946
975
947 if (!PyArg_ParseTuple(args, "O", &val))
976 if (!PyArg_ParseTuple(args, "O", &val))
948 return NULL;
977 return NULL;
949 if (node_check(val, &node, &nodelen) == -1)
978 if (node_check(val, &node, &nodelen) == -1)
950 return NULL;
979 return NULL;
951 rev = index_find_node(self, node, nodelen);
980 rev = index_find_node(self, node, nodelen);
952 if (rev == -3)
981 if (rev == -3)
953 return NULL;
982 return NULL;
954 if (rev == -2)
983 if (rev == -2)
955 Py_RETURN_NONE;
984 Py_RETURN_NONE;
956 return PyInt_FromLong(rev);
985 return PyInt_FromLong(rev);
957 }
986 }
958
987
959 static int index_contains(indexObject *self, PyObject *value)
988 static int index_contains(indexObject *self, PyObject *value)
960 {
989 {
961 char *node;
990 char *node;
962 Py_ssize_t nodelen;
991 Py_ssize_t nodelen;
963
992
964 if (PyInt_Check(value)) {
993 if (PyInt_Check(value)) {
965 long rev = PyInt_AS_LONG(value);
994 long rev = PyInt_AS_LONG(value);
966 return rev >= -1 && rev < index_length(self);
995 return rev >= -1 && rev < index_length(self);
967 }
996 }
968
997
969 if (node_check(value, &node, &nodelen) == -1)
998 if (node_check(value, &node, &nodelen) == -1)
970 return -1;
999 return -1;
971
1000
972 switch (index_find_node(self, node, nodelen)) {
1001 switch (index_find_node(self, node, nodelen)) {
973 case -3:
1002 case -3:
974 return -1;
1003 return -1;
975 case -2:
1004 case -2:
976 return 0;
1005 return 0;
977 default:
1006 default:
978 return 1;
1007 return 1;
979 }
1008 }
980 }
1009 }
981
1010
982 /*
1011 /*
983 * Invalidate any trie entries introduced by added revs.
1012 * Invalidate any trie entries introduced by added revs.
984 */
1013 */
985 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1014 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
986 {
1015 {
987 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1016 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
988
1017
989 for (i = start; i < len; i++) {
1018 for (i = start; i < len; i++) {
990 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1019 PyObject *tuple = PyList_GET_ITEM(self->added, i);
991 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1020 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
992
1021
993 nt_insert(self, PyString_AS_STRING(node), -1);
1022 nt_insert(self, PyString_AS_STRING(node), -1);
994 }
1023 }
995
1024
996 if (start == 0)
1025 if (start == 0)
997 Py_CLEAR(self->added);
1026 Py_CLEAR(self->added);
998 }
1027 }
999
1028
1000 /*
1029 /*
1001 * Delete a numeric range of revs, which must be at the end of the
1030 * Delete a numeric range of revs, which must be at the end of the
1002 * range, but exclude the sentinel nullid entry.
1031 * range, but exclude the sentinel nullid entry.
1003 */
1032 */
1004 static int index_slice_del(indexObject *self, PyObject *item)
1033 static int index_slice_del(indexObject *self, PyObject *item)
1005 {
1034 {
1006 Py_ssize_t start, stop, step, slicelength;
1035 Py_ssize_t start, stop, step, slicelength;
1007 Py_ssize_t length = index_length(self);
1036 Py_ssize_t length = index_length(self);
1008 int ret = 0;
1037 int ret = 0;
1009
1038
1010 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1039 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1011 &start, &stop, &step, &slicelength) < 0)
1040 &start, &stop, &step, &slicelength) < 0)
1012 return -1;
1041 return -1;
1013
1042
1014 if (slicelength <= 0)
1043 if (slicelength <= 0)
1015 return 0;
1044 return 0;
1016
1045
1017 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1046 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1018 stop = start;
1047 stop = start;
1019
1048
1020 if (step < 0) {
1049 if (step < 0) {
1021 stop = start + 1;
1050 stop = start + 1;
1022 start = stop + step*(slicelength - 1) - 1;
1051 start = stop + step*(slicelength - 1) - 1;
1023 step = -step;
1052 step = -step;
1024 }
1053 }
1025
1054
1026 if (step != 1) {
1055 if (step != 1) {
1027 PyErr_SetString(PyExc_ValueError,
1056 PyErr_SetString(PyExc_ValueError,
1028 "revlog index delete requires step size of 1");
1057 "revlog index delete requires step size of 1");
1029 return -1;
1058 return -1;
1030 }
1059 }
1031
1060
1032 if (stop != length - 1) {
1061 if (stop != length - 1) {
1033 PyErr_SetString(PyExc_IndexError,
1062 PyErr_SetString(PyExc_IndexError,
1034 "revlog index deletion indices are invalid");
1063 "revlog index deletion indices are invalid");
1035 return -1;
1064 return -1;
1036 }
1065 }
1037
1066
1038 if (start < self->length - 1) {
1067 if (start < self->length - 1) {
1039 if (self->nt) {
1068 if (self->nt) {
1040 Py_ssize_t i;
1069 Py_ssize_t i;
1041
1070
1042 for (i = start + 1; i < self->length - 1; i++) {
1071 for (i = start + 1; i < self->length - 1; i++) {
1043 const char *node = index_node(self, i);
1072 const char *node = index_node(self, i);
1044
1073
1045 if (node)
1074 if (node)
1046 nt_insert(self, node, -1);
1075 nt_insert(self, node, -1);
1047 }
1076 }
1048 if (self->added)
1077 if (self->added)
1049 nt_invalidate_added(self, 0);
1078 nt_invalidate_added(self, 0);
1050 if (self->ntrev > start)
1079 if (self->ntrev > start)
1051 self->ntrev = (int)start;
1080 self->ntrev = (int)start;
1052 }
1081 }
1053 self->length = start + 1;
1082 self->length = start + 1;
1054 if (start < self->raw_length)
1083 if (start < self->raw_length)
1055 self->raw_length = start;
1084 self->raw_length = start;
1056 goto done;
1085 goto done;
1057 }
1086 }
1058
1087
1059 if (self->nt) {
1088 if (self->nt) {
1060 nt_invalidate_added(self, start - self->length + 1);
1089 nt_invalidate_added(self, start - self->length + 1);
1061 if (self->ntrev > start)
1090 if (self->ntrev > start)
1062 self->ntrev = (int)start;
1091 self->ntrev = (int)start;
1063 }
1092 }
1064 if (self->added)
1093 if (self->added)
1065 ret = PyList_SetSlice(self->added, start - self->length + 1,
1094 ret = PyList_SetSlice(self->added, start - self->length + 1,
1066 PyList_GET_SIZE(self->added), NULL);
1095 PyList_GET_SIZE(self->added), NULL);
1067 done:
1096 done:
1097 Py_CLEAR(self->headrevs);
1068 return ret;
1098 return ret;
1069 }
1099 }
1070
1100
1071 /*
1101 /*
1072 * Supported ops:
1102 * Supported ops:
1073 *
1103 *
1074 * slice deletion
1104 * slice deletion
1075 * string assignment (extend node->rev mapping)
1105 * string assignment (extend node->rev mapping)
1076 * string deletion (shrink node->rev mapping)
1106 * string deletion (shrink node->rev mapping)
1077 */
1107 */
1078 static int index_assign_subscript(indexObject *self, PyObject *item,
1108 static int index_assign_subscript(indexObject *self, PyObject *item,
1079 PyObject *value)
1109 PyObject *value)
1080 {
1110 {
1081 char *node;
1111 char *node;
1082 Py_ssize_t nodelen;
1112 Py_ssize_t nodelen;
1083 long rev;
1113 long rev;
1084
1114
1085 if (PySlice_Check(item) && value == NULL)
1115 if (PySlice_Check(item) && value == NULL)
1086 return index_slice_del(self, item);
1116 return index_slice_del(self, item);
1087
1117
1088 if (node_check(item, &node, &nodelen) == -1)
1118 if (node_check(item, &node, &nodelen) == -1)
1089 return -1;
1119 return -1;
1090
1120
1091 if (value == NULL)
1121 if (value == NULL)
1092 return self->nt ? nt_insert(self, node, -1) : 0;
1122 return self->nt ? nt_insert(self, node, -1) : 0;
1093 rev = PyInt_AsLong(value);
1123 rev = PyInt_AsLong(value);
1094 if (rev > INT_MAX || rev < 0) {
1124 if (rev > INT_MAX || rev < 0) {
1095 if (!PyErr_Occurred())
1125 if (!PyErr_Occurred())
1096 PyErr_SetString(PyExc_ValueError, "rev out of range");
1126 PyErr_SetString(PyExc_ValueError, "rev out of range");
1097 return -1;
1127 return -1;
1098 }
1128 }
1099 return nt_insert(self, node, (int)rev);
1129 return nt_insert(self, node, (int)rev);
1100 }
1130 }
1101
1131
1102 /*
1132 /*
1103 * Find all RevlogNG entries in an index that has inline data. Update
1133 * Find all RevlogNG entries in an index that has inline data. Update
1104 * the optional "offsets" table with those entries.
1134 * the optional "offsets" table with those entries.
1105 */
1135 */
1106 static long inline_scan(indexObject *self, const char **offsets)
1136 static long inline_scan(indexObject *self, const char **offsets)
1107 {
1137 {
1108 const char *data = PyString_AS_STRING(self->data);
1138 const char *data = PyString_AS_STRING(self->data);
1109 const char *end = data + PyString_GET_SIZE(self->data);
1139 const char *end = data + PyString_GET_SIZE(self->data);
1110 const long hdrsize = 64;
1140 const long hdrsize = 64;
1111 long incr = hdrsize;
1141 long incr = hdrsize;
1112 Py_ssize_t len = 0;
1142 Py_ssize_t len = 0;
1113
1143
1114 while (data + hdrsize <= end) {
1144 while (data + hdrsize <= end) {
1115 uint32_t comp_len;
1145 uint32_t comp_len;
1116 const char *old_data;
1146 const char *old_data;
1117 /* 3rd element of header is length of compressed inline data */
1147 /* 3rd element of header is length of compressed inline data */
1118 comp_len = getbe32(data + 8);
1148 comp_len = getbe32(data + 8);
1119 incr = hdrsize + comp_len;
1149 incr = hdrsize + comp_len;
1120 if (incr < hdrsize)
1150 if (incr < hdrsize)
1121 break;
1151 break;
1122 if (offsets)
1152 if (offsets)
1123 offsets[len] = data;
1153 offsets[len] = data;
1124 len++;
1154 len++;
1125 old_data = data;
1155 old_data = data;
1126 data += incr;
1156 data += incr;
1127 if (data <= old_data)
1157 if (data <= old_data)
1128 break;
1158 break;
1129 }
1159 }
1130
1160
1131 if (data != end && data + hdrsize != end) {
1161 if (data != end && data + hdrsize != end) {
1132 if (!PyErr_Occurred())
1162 if (!PyErr_Occurred())
1133 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1163 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1134 return -1;
1164 return -1;
1135 }
1165 }
1136
1166
1137 return len;
1167 return len;
1138 }
1168 }
1139
1169
1140 static int index_init(indexObject *self, PyObject *args)
1170 static int index_init(indexObject *self, PyObject *args)
1141 {
1171 {
1142 PyObject *data_obj, *inlined_obj;
1172 PyObject *data_obj, *inlined_obj;
1143 Py_ssize_t size;
1173 Py_ssize_t size;
1144
1174
1145 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1175 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1146 return -1;
1176 return -1;
1147 if (!PyString_Check(data_obj)) {
1177 if (!PyString_Check(data_obj)) {
1148 PyErr_SetString(PyExc_TypeError, "data is not a string");
1178 PyErr_SetString(PyExc_TypeError, "data is not a string");
1149 return -1;
1179 return -1;
1150 }
1180 }
1151 size = PyString_GET_SIZE(data_obj);
1181 size = PyString_GET_SIZE(data_obj);
1152
1182
1153 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1183 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1154 self->data = data_obj;
1184 self->data = data_obj;
1155 self->cache = NULL;
1185 self->cache = NULL;
1156
1186
1157 self->added = NULL;
1187 self->added = NULL;
1188 self->headrevs = NULL;
1158 self->offsets = NULL;
1189 self->offsets = NULL;
1159 self->nt = NULL;
1190 self->nt = NULL;
1160 self->ntlength = self->ntcapacity = 0;
1191 self->ntlength = self->ntcapacity = 0;
1161 self->ntdepth = self->ntsplits = 0;
1192 self->ntdepth = self->ntsplits = 0;
1162 self->ntlookups = self->ntmisses = 0;
1193 self->ntlookups = self->ntmisses = 0;
1163 self->ntrev = -1;
1194 self->ntrev = -1;
1164 Py_INCREF(self->data);
1195 Py_INCREF(self->data);
1165
1196
1166 if (self->inlined) {
1197 if (self->inlined) {
1167 long len = inline_scan(self, NULL);
1198 long len = inline_scan(self, NULL);
1168 if (len == -1)
1199 if (len == -1)
1169 goto bail;
1200 goto bail;
1170 self->raw_length = len;
1201 self->raw_length = len;
1171 self->length = len + 1;
1202 self->length = len + 1;
1172 } else {
1203 } else {
1173 if (size % 64) {
1204 if (size % 64) {
1174 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1205 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1175 goto bail;
1206 goto bail;
1176 }
1207 }
1177 self->raw_length = size / 64;
1208 self->raw_length = size / 64;
1178 self->length = self->raw_length + 1;
1209 self->length = self->raw_length + 1;
1179 }
1210 }
1180
1211
1181 return 0;
1212 return 0;
1182 bail:
1213 bail:
1183 return -1;
1214 return -1;
1184 }
1215 }
1185
1216
1186 static PyObject *index_nodemap(indexObject *self)
1217 static PyObject *index_nodemap(indexObject *self)
1187 {
1218 {
1188 Py_INCREF(self);
1219 Py_INCREF(self);
1189 return (PyObject *)self;
1220 return (PyObject *)self;
1190 }
1221 }
1191
1222
1192 static void index_dealloc(indexObject *self)
1223 static void index_dealloc(indexObject *self)
1193 {
1224 {
1194 _index_clearcaches(self);
1225 _index_clearcaches(self);
1195 Py_DECREF(self->data);
1226 Py_DECREF(self->data);
1196 Py_XDECREF(self->added);
1227 Py_XDECREF(self->added);
1197 PyObject_Del(self);
1228 PyObject_Del(self);
1198 }
1229 }
1199
1230
1200 static PySequenceMethods index_sequence_methods = {
1231 static PySequenceMethods index_sequence_methods = {
1201 (lenfunc)index_length, /* sq_length */
1232 (lenfunc)index_length, /* sq_length */
1202 0, /* sq_concat */
1233 0, /* sq_concat */
1203 0, /* sq_repeat */
1234 0, /* sq_repeat */
1204 (ssizeargfunc)index_get, /* sq_item */
1235 (ssizeargfunc)index_get, /* sq_item */
1205 0, /* sq_slice */
1236 0, /* sq_slice */
1206 0, /* sq_ass_item */
1237 0, /* sq_ass_item */
1207 0, /* sq_ass_slice */
1238 0, /* sq_ass_slice */
1208 (objobjproc)index_contains, /* sq_contains */
1239 (objobjproc)index_contains, /* sq_contains */
1209 };
1240 };
1210
1241
1211 static PyMappingMethods index_mapping_methods = {
1242 static PyMappingMethods index_mapping_methods = {
1212 (lenfunc)index_length, /* mp_length */
1243 (lenfunc)index_length, /* mp_length */
1213 (binaryfunc)index_getitem, /* mp_subscript */
1244 (binaryfunc)index_getitem, /* mp_subscript */
1214 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1245 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1215 };
1246 };
1216
1247
1217 static PyMethodDef index_methods[] = {
1248 static PyMethodDef index_methods[] = {
1218 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1249 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1219 "clear the index caches"},
1250 "clear the index caches"},
1220 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1251 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1221 "get an index entry"},
1252 "get an index entry"},
1222 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1253 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1223 "get head revisions"},
1254 "get head revisions"},
1224 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1255 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1225 "insert an index entry"},
1256 "insert an index entry"},
1226 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1257 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1227 "match a potentially ambiguous node ID"},
1258 "match a potentially ambiguous node ID"},
1228 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1259 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1229 "stats for the index"},
1260 "stats for the index"},
1230 {NULL} /* Sentinel */
1261 {NULL} /* Sentinel */
1231 };
1262 };
1232
1263
1233 static PyGetSetDef index_getset[] = {
1264 static PyGetSetDef index_getset[] = {
1234 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1265 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1235 {NULL} /* Sentinel */
1266 {NULL} /* Sentinel */
1236 };
1267 };
1237
1268
1238 static PyTypeObject indexType = {
1269 static PyTypeObject indexType = {
1239 PyObject_HEAD_INIT(NULL)
1270 PyObject_HEAD_INIT(NULL)
1240 0, /* ob_size */
1271 0, /* ob_size */
1241 "parsers.index", /* tp_name */
1272 "parsers.index", /* tp_name */
1242 sizeof(indexObject), /* tp_basicsize */
1273 sizeof(indexObject), /* tp_basicsize */
1243 0, /* tp_itemsize */
1274 0, /* tp_itemsize */
1244 (destructor)index_dealloc, /* tp_dealloc */
1275 (destructor)index_dealloc, /* tp_dealloc */
1245 0, /* tp_print */
1276 0, /* tp_print */
1246 0, /* tp_getattr */
1277 0, /* tp_getattr */
1247 0, /* tp_setattr */
1278 0, /* tp_setattr */
1248 0, /* tp_compare */
1279 0, /* tp_compare */
1249 0, /* tp_repr */
1280 0, /* tp_repr */
1250 0, /* tp_as_number */
1281 0, /* tp_as_number */
1251 &index_sequence_methods, /* tp_as_sequence */
1282 &index_sequence_methods, /* tp_as_sequence */
1252 &index_mapping_methods, /* tp_as_mapping */
1283 &index_mapping_methods, /* tp_as_mapping */
1253 0, /* tp_hash */
1284 0, /* tp_hash */
1254 0, /* tp_call */
1285 0, /* tp_call */
1255 0, /* tp_str */
1286 0, /* tp_str */
1256 0, /* tp_getattro */
1287 0, /* tp_getattro */
1257 0, /* tp_setattro */
1288 0, /* tp_setattro */
1258 0, /* tp_as_buffer */
1289 0, /* tp_as_buffer */
1259 Py_TPFLAGS_DEFAULT, /* tp_flags */
1290 Py_TPFLAGS_DEFAULT, /* tp_flags */
1260 "revlog index", /* tp_doc */
1291 "revlog index", /* tp_doc */
1261 0, /* tp_traverse */
1292 0, /* tp_traverse */
1262 0, /* tp_clear */
1293 0, /* tp_clear */
1263 0, /* tp_richcompare */
1294 0, /* tp_richcompare */
1264 0, /* tp_weaklistoffset */
1295 0, /* tp_weaklistoffset */
1265 0, /* tp_iter */
1296 0, /* tp_iter */
1266 0, /* tp_iternext */
1297 0, /* tp_iternext */
1267 index_methods, /* tp_methods */
1298 index_methods, /* tp_methods */
1268 0, /* tp_members */
1299 0, /* tp_members */
1269 index_getset, /* tp_getset */
1300 index_getset, /* tp_getset */
1270 0, /* tp_base */
1301 0, /* tp_base */
1271 0, /* tp_dict */
1302 0, /* tp_dict */
1272 0, /* tp_descr_get */
1303 0, /* tp_descr_get */
1273 0, /* tp_descr_set */
1304 0, /* tp_descr_set */
1274 0, /* tp_dictoffset */
1305 0, /* tp_dictoffset */
1275 (initproc)index_init, /* tp_init */
1306 (initproc)index_init, /* tp_init */
1276 0, /* tp_alloc */
1307 0, /* tp_alloc */
1277 };
1308 };
1278
1309
1279 /*
1310 /*
1280 * returns a tuple of the form (index, index, cache) with elements as
1311 * returns a tuple of the form (index, index, cache) with elements as
1281 * follows:
1312 * follows:
1282 *
1313 *
1283 * index: an index object that lazily parses RevlogNG records
1314 * index: an index object that lazily parses RevlogNG records
1284 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1315 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1285 *
1316 *
1286 * added complications are for backwards compatibility
1317 * added complications are for backwards compatibility
1287 */
1318 */
1288 static PyObject *parse_index2(PyObject *self, PyObject *args)
1319 static PyObject *parse_index2(PyObject *self, PyObject *args)
1289 {
1320 {
1290 PyObject *tuple = NULL, *cache = NULL;
1321 PyObject *tuple = NULL, *cache = NULL;
1291 indexObject *idx;
1322 indexObject *idx;
1292 int ret;
1323 int ret;
1293
1324
1294 idx = PyObject_New(indexObject, &indexType);
1325 idx = PyObject_New(indexObject, &indexType);
1295 if (idx == NULL)
1326 if (idx == NULL)
1296 goto bail;
1327 goto bail;
1297
1328
1298 ret = index_init(idx, args);
1329 ret = index_init(idx, args);
1299 if (ret == -1)
1330 if (ret == -1)
1300 goto bail;
1331 goto bail;
1301
1332
1302 if (idx->inlined) {
1333 if (idx->inlined) {
1303 cache = Py_BuildValue("iO", 0, idx->data);
1334 cache = Py_BuildValue("iO", 0, idx->data);
1304 if (cache == NULL)
1335 if (cache == NULL)
1305 goto bail;
1336 goto bail;
1306 } else {
1337 } else {
1307 cache = Py_None;
1338 cache = Py_None;
1308 Py_INCREF(cache);
1339 Py_INCREF(cache);
1309 }
1340 }
1310
1341
1311 tuple = Py_BuildValue("NN", idx, cache);
1342 tuple = Py_BuildValue("NN", idx, cache);
1312 if (!tuple)
1343 if (!tuple)
1313 goto bail;
1344 goto bail;
1314 return tuple;
1345 return tuple;
1315
1346
1316 bail:
1347 bail:
1317 Py_XDECREF(idx);
1348 Py_XDECREF(idx);
1318 Py_XDECREF(cache);
1349 Py_XDECREF(cache);
1319 Py_XDECREF(tuple);
1350 Py_XDECREF(tuple);
1320 return NULL;
1351 return NULL;
1321 }
1352 }
1322
1353
1323 static char parsers_doc[] = "Efficient content parsing.";
1354 static char parsers_doc[] = "Efficient content parsing.";
1324
1355
1325 static PyMethodDef methods[] = {
1356 static PyMethodDef methods[] = {
1326 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1357 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1327 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1358 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1328 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
1359 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
1329 {NULL, NULL}
1360 {NULL, NULL}
1330 };
1361 };
1331
1362
1332 static void module_init(PyObject *mod)
1363 static void module_init(PyObject *mod)
1333 {
1364 {
1334 indexType.tp_new = PyType_GenericNew;
1365 indexType.tp_new = PyType_GenericNew;
1335 if (PyType_Ready(&indexType) < 0)
1366 if (PyType_Ready(&indexType) < 0)
1336 return;
1367 return;
1337 Py_INCREF(&indexType);
1368 Py_INCREF(&indexType);
1338
1369
1339 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
1370 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
1340
1371
1341 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
1372 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
1342 -1, -1, -1, -1, nullid, 20);
1373 -1, -1, -1, -1, nullid, 20);
1343 if (nullentry)
1374 if (nullentry)
1344 PyObject_GC_UnTrack(nullentry);
1375 PyObject_GC_UnTrack(nullentry);
1345 }
1376 }
1346
1377
1347 #ifdef IS_PY3K
1378 #ifdef IS_PY3K
1348 static struct PyModuleDef parsers_module = {
1379 static struct PyModuleDef parsers_module = {
1349 PyModuleDef_HEAD_INIT,
1380 PyModuleDef_HEAD_INIT,
1350 "parsers",
1381 "parsers",
1351 parsers_doc,
1382 parsers_doc,
1352 -1,
1383 -1,
1353 methods
1384 methods
1354 };
1385 };
1355
1386
1356 PyMODINIT_FUNC PyInit_parsers(void)
1387 PyMODINIT_FUNC PyInit_parsers(void)
1357 {
1388 {
1358 PyObject *mod = PyModule_Create(&parsers_module);
1389 PyObject *mod = PyModule_Create(&parsers_module);
1359 module_init(mod);
1390 module_init(mod);
1360 return mod;
1391 return mod;
1361 }
1392 }
1362 #else
1393 #else
1363 PyMODINIT_FUNC initparsers(void)
1394 PyMODINIT_FUNC initparsers(void)
1364 {
1395 {
1365 PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc);
1396 PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc);
1366 module_init(mod);
1397 module_init(mod);
1367 }
1398 }
1368 #endif
1399 #endif
General Comments 0
You need to be logged in to leave comments. Login now