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