##// END OF EJS Templates
parsers: fix a memleak, and add a clearcaches method to the index...
Bryan O'Sullivan -
r16370:28bb4daf default
parent child Browse files
Show More
@@ -1,720 +1,740 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 int hexdigit(char c)
16 static int hexdigit(char c)
17 {
17 {
18 if (c >= '0' && c <= '9')
18 if (c >= '0' && c <= '9')
19 return c - '0';
19 return c - '0';
20 if (c >= 'a' && c <= 'f')
20 if (c >= 'a' && c <= 'f')
21 return c - 'a' + 10;
21 return c - 'a' + 10;
22 if (c >= 'A' && c <= 'F')
22 if (c >= 'A' && c <= 'F')
23 return c - 'A' + 10;
23 return c - 'A' + 10;
24
24
25 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
25 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
26 return 0;
26 return 0;
27 }
27 }
28
28
29 /*
29 /*
30 * Turn a hex-encoded string into binary.
30 * Turn a hex-encoded string into binary.
31 */
31 */
32 static PyObject *unhexlify(const char *str, int len)
32 static PyObject *unhexlify(const char *str, int len)
33 {
33 {
34 PyObject *ret;
34 PyObject *ret;
35 const char *c;
35 const char *c;
36 char *d;
36 char *d;
37
37
38 ret = PyBytes_FromStringAndSize(NULL, len / 2);
38 ret = PyBytes_FromStringAndSize(NULL, len / 2);
39
39
40 if (!ret)
40 if (!ret)
41 return NULL;
41 return NULL;
42
42
43 d = PyBytes_AsString(ret);
43 d = PyBytes_AsString(ret);
44
44
45 for (c = str; c < str + len;) {
45 for (c = str; c < str + len;) {
46 int hi = hexdigit(*c++);
46 int hi = hexdigit(*c++);
47 int lo = hexdigit(*c++);
47 int lo = hexdigit(*c++);
48 *d++ = (hi << 4) | lo;
48 *d++ = (hi << 4) | lo;
49 }
49 }
50
50
51 return ret;
51 return ret;
52 }
52 }
53
53
54 /*
54 /*
55 * This code assumes that a manifest is stitched together with newline
55 * This code assumes that a manifest is stitched together with newline
56 * ('\n') characters.
56 * ('\n') characters.
57 */
57 */
58 static PyObject *parse_manifest(PyObject *self, PyObject *args)
58 static PyObject *parse_manifest(PyObject *self, PyObject *args)
59 {
59 {
60 PyObject *mfdict, *fdict;
60 PyObject *mfdict, *fdict;
61 char *str, *cur, *start, *zero;
61 char *str, *cur, *start, *zero;
62 int len;
62 int len;
63
63
64 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
64 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
65 &PyDict_Type, &mfdict,
65 &PyDict_Type, &mfdict,
66 &PyDict_Type, &fdict,
66 &PyDict_Type, &fdict,
67 &str, &len))
67 &str, &len))
68 goto quit;
68 goto quit;
69
69
70 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
70 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
71 PyObject *file = NULL, *node = NULL;
71 PyObject *file = NULL, *node = NULL;
72 PyObject *flags = NULL;
72 PyObject *flags = NULL;
73 int nlen;
73 int nlen;
74
74
75 if (!*cur) {
75 if (!*cur) {
76 zero = cur;
76 zero = cur;
77 continue;
77 continue;
78 }
78 }
79 else if (*cur != '\n')
79 else if (*cur != '\n')
80 continue;
80 continue;
81
81
82 if (!zero) {
82 if (!zero) {
83 PyErr_SetString(PyExc_ValueError,
83 PyErr_SetString(PyExc_ValueError,
84 "manifest entry has no separator");
84 "manifest entry has no separator");
85 goto quit;
85 goto quit;
86 }
86 }
87
87
88 file = PyBytes_FromStringAndSize(start, zero - start);
88 file = PyBytes_FromStringAndSize(start, zero - start);
89
89
90 if (!file)
90 if (!file)
91 goto bail;
91 goto bail;
92
92
93 nlen = cur - zero - 1;
93 nlen = cur - zero - 1;
94
94
95 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
95 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
96 if (!node)
96 if (!node)
97 goto bail;
97 goto bail;
98
98
99 if (nlen > 40) {
99 if (nlen > 40) {
100 flags = PyBytes_FromStringAndSize(zero + 41,
100 flags = PyBytes_FromStringAndSize(zero + 41,
101 nlen - 40);
101 nlen - 40);
102 if (!flags)
102 if (!flags)
103 goto bail;
103 goto bail;
104
104
105 if (PyDict_SetItem(fdict, file, flags) == -1)
105 if (PyDict_SetItem(fdict, file, flags) == -1)
106 goto bail;
106 goto bail;
107 }
107 }
108
108
109 if (PyDict_SetItem(mfdict, file, node) == -1)
109 if (PyDict_SetItem(mfdict, file, node) == -1)
110 goto bail;
110 goto bail;
111
111
112 start = cur + 1;
112 start = cur + 1;
113 zero = NULL;
113 zero = NULL;
114
114
115 Py_XDECREF(flags);
115 Py_XDECREF(flags);
116 Py_XDECREF(node);
116 Py_XDECREF(node);
117 Py_XDECREF(file);
117 Py_XDECREF(file);
118 continue;
118 continue;
119 bail:
119 bail:
120 Py_XDECREF(flags);
120 Py_XDECREF(flags);
121 Py_XDECREF(node);
121 Py_XDECREF(node);
122 Py_XDECREF(file);
122 Py_XDECREF(file);
123 goto quit;
123 goto quit;
124 }
124 }
125
125
126 if (len > 0 && *(cur - 1) != '\n') {
126 if (len > 0 && *(cur - 1) != '\n') {
127 PyErr_SetString(PyExc_ValueError,
127 PyErr_SetString(PyExc_ValueError,
128 "manifest contains trailing garbage");
128 "manifest contains trailing garbage");
129 goto quit;
129 goto quit;
130 }
130 }
131
131
132 Py_INCREF(Py_None);
132 Py_INCREF(Py_None);
133 return Py_None;
133 return Py_None;
134 quit:
134 quit:
135 return NULL;
135 return NULL;
136 }
136 }
137
137
138 #ifdef _WIN32
138 #ifdef _WIN32
139 #ifdef _MSC_VER
139 #ifdef _MSC_VER
140 /* msvc 6.0 has problems */
140 /* msvc 6.0 has problems */
141 #define inline __inline
141 #define inline __inline
142 typedef unsigned long uint32_t;
142 typedef unsigned long uint32_t;
143 typedef unsigned __int64 uint64_t;
143 typedef unsigned __int64 uint64_t;
144 #else
144 #else
145 #include <stdint.h>
145 #include <stdint.h>
146 #endif
146 #endif
147 static uint32_t ntohl(uint32_t x)
147 static uint32_t ntohl(uint32_t x)
148 {
148 {
149 return ((x & 0x000000ffUL) << 24) |
149 return ((x & 0x000000ffUL) << 24) |
150 ((x & 0x0000ff00UL) << 8) |
150 ((x & 0x0000ff00UL) << 8) |
151 ((x & 0x00ff0000UL) >> 8) |
151 ((x & 0x00ff0000UL) >> 8) |
152 ((x & 0xff000000UL) >> 24);
152 ((x & 0xff000000UL) >> 24);
153 }
153 }
154 #else
154 #else
155 /* not windows */
155 /* not windows */
156 #include <sys/types.h>
156 #include <sys/types.h>
157 #if defined __BEOS__ && !defined __HAIKU__
157 #if defined __BEOS__ && !defined __HAIKU__
158 #include <ByteOrder.h>
158 #include <ByteOrder.h>
159 #else
159 #else
160 #include <arpa/inet.h>
160 #include <arpa/inet.h>
161 #endif
161 #endif
162 #include <inttypes.h>
162 #include <inttypes.h>
163 #endif
163 #endif
164
164
165 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
165 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
166 {
166 {
167 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
167 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
168 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
168 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
169 char *str, *cur, *end, *cpos;
169 char *str, *cur, *end, *cpos;
170 int state, mode, size, mtime;
170 int state, mode, size, mtime;
171 unsigned int flen;
171 unsigned int flen;
172 int len;
172 int len;
173 uint32_t decode[4]; /* for alignment */
173 uint32_t decode[4]; /* for alignment */
174
174
175 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
175 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
176 &PyDict_Type, &dmap,
176 &PyDict_Type, &dmap,
177 &PyDict_Type, &cmap,
177 &PyDict_Type, &cmap,
178 &str, &len))
178 &str, &len))
179 goto quit;
179 goto quit;
180
180
181 /* read parents */
181 /* read parents */
182 if (len < 40)
182 if (len < 40)
183 goto quit;
183 goto quit;
184
184
185 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
185 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
186 if (!parents)
186 if (!parents)
187 goto quit;
187 goto quit;
188
188
189 /* read filenames */
189 /* read filenames */
190 cur = str + 40;
190 cur = str + 40;
191 end = str + len;
191 end = str + len;
192
192
193 while (cur < end - 17) {
193 while (cur < end - 17) {
194 /* unpack header */
194 /* unpack header */
195 state = *cur;
195 state = *cur;
196 memcpy(decode, cur + 1, 16);
196 memcpy(decode, cur + 1, 16);
197 mode = ntohl(decode[0]);
197 mode = ntohl(decode[0]);
198 size = ntohl(decode[1]);
198 size = ntohl(decode[1]);
199 mtime = ntohl(decode[2]);
199 mtime = ntohl(decode[2]);
200 flen = ntohl(decode[3]);
200 flen = ntohl(decode[3]);
201 cur += 17;
201 cur += 17;
202 if (cur + flen > end || cur + flen < cur) {
202 if (cur + flen > end || cur + flen < cur) {
203 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
203 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
204 goto quit;
204 goto quit;
205 }
205 }
206
206
207 entry = Py_BuildValue("ciii", state, mode, size, mtime);
207 entry = Py_BuildValue("ciii", state, mode, size, mtime);
208 if (!entry)
208 if (!entry)
209 goto quit;
209 goto quit;
210 PyObject_GC_UnTrack(entry); /* don't waste time with this */
210 PyObject_GC_UnTrack(entry); /* don't waste time with this */
211
211
212 cpos = memchr(cur, 0, flen);
212 cpos = memchr(cur, 0, flen);
213 if (cpos) {
213 if (cpos) {
214 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
214 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
215 cname = PyBytes_FromStringAndSize(cpos + 1,
215 cname = PyBytes_FromStringAndSize(cpos + 1,
216 flen - (cpos - cur) - 1);
216 flen - (cpos - cur) - 1);
217 if (!fname || !cname ||
217 if (!fname || !cname ||
218 PyDict_SetItem(cmap, fname, cname) == -1 ||
218 PyDict_SetItem(cmap, fname, cname) == -1 ||
219 PyDict_SetItem(dmap, fname, entry) == -1)
219 PyDict_SetItem(dmap, fname, entry) == -1)
220 goto quit;
220 goto quit;
221 Py_DECREF(cname);
221 Py_DECREF(cname);
222 } else {
222 } else {
223 fname = PyBytes_FromStringAndSize(cur, flen);
223 fname = PyBytes_FromStringAndSize(cur, flen);
224 if (!fname ||
224 if (!fname ||
225 PyDict_SetItem(dmap, fname, entry) == -1)
225 PyDict_SetItem(dmap, fname, entry) == -1)
226 goto quit;
226 goto quit;
227 }
227 }
228 cur += flen;
228 cur += flen;
229 Py_DECREF(fname);
229 Py_DECREF(fname);
230 Py_DECREF(entry);
230 Py_DECREF(entry);
231 fname = cname = entry = NULL;
231 fname = cname = entry = NULL;
232 }
232 }
233
233
234 ret = parents;
234 ret = parents;
235 Py_INCREF(ret);
235 Py_INCREF(ret);
236 quit:
236 quit:
237 Py_XDECREF(fname);
237 Py_XDECREF(fname);
238 Py_XDECREF(cname);
238 Py_XDECREF(cname);
239 Py_XDECREF(entry);
239 Py_XDECREF(entry);
240 Py_XDECREF(parents);
240 Py_XDECREF(parents);
241 return ret;
241 return ret;
242 }
242 }
243
243
244 /*
244 /*
245 * A list-like object that decodes the contents of a RevlogNG index
245 * A list-like object that decodes the contents of a RevlogNG index
246 * file on demand. It has limited support for insert and delete at the
246 * file on demand. It has limited support for insert and delete at the
247 * last element before the end. The last entry is always a sentinel
247 * last element before the end. The last entry is always a sentinel
248 * nullid.
248 * nullid.
249 */
249 */
250 typedef struct {
250 typedef struct {
251 PyObject_HEAD
251 PyObject_HEAD
252 /* Type-specific fields go here. */
252 /* Type-specific fields go here. */
253 PyObject *data; /* raw bytes of index */
253 PyObject *data; /* raw bytes of index */
254 PyObject **cache; /* cached tuples */
254 PyObject **cache; /* cached tuples */
255 const char **offsets; /* populated on demand */
255 const char **offsets; /* populated on demand */
256 Py_ssize_t raw_length; /* original number of elements */
256 Py_ssize_t raw_length; /* original number of elements */
257 Py_ssize_t length; /* current number of elements */
257 Py_ssize_t length; /* current number of elements */
258 PyObject *added; /* populated on demand */
258 PyObject *added; /* populated on demand */
259 int inlined;
259 int inlined;
260 } indexObject;
260 } indexObject;
261
261
262 static Py_ssize_t index_length(indexObject *self)
262 static Py_ssize_t index_length(indexObject *self)
263 {
263 {
264 if (self->added == NULL)
264 if (self->added == NULL)
265 return self->length;
265 return self->length;
266 return self->length + PyList_GET_SIZE(self->added);
266 return self->length + PyList_GET_SIZE(self->added);
267 }
267 }
268
268
269 static PyObject *nullentry;
269 static PyObject *nullentry;
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 const char *tuple_format = "Kiiiiiis#";
274 static const char *tuple_format = "Kiiiiiis#";
275 #else
275 #else
276 static const char *tuple_format = "kiiiiiis#";
276 static const char *tuple_format = "kiiiiiis#";
277 #endif
277 #endif
278
278
279 /* RevlogNG format (all in big endian, data may be inlined):
279 /* RevlogNG format (all in big endian, data may be inlined):
280 * 6 bytes: offset
280 * 6 bytes: offset
281 * 2 bytes: flags
281 * 2 bytes: flags
282 * 4 bytes: compressed length
282 * 4 bytes: compressed length
283 * 4 bytes: uncompressed length
283 * 4 bytes: uncompressed length
284 * 4 bytes: base revision
284 * 4 bytes: base revision
285 * 4 bytes: link revision
285 * 4 bytes: link revision
286 * 4 bytes: parent 1 revision
286 * 4 bytes: parent 1 revision
287 * 4 bytes: parent 2 revision
287 * 4 bytes: parent 2 revision
288 * 32 bytes: nodeid (only 20 bytes used)
288 * 32 bytes: nodeid (only 20 bytes used)
289 */
289 */
290 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
290 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
291 {
291 {
292 uint32_t decode[8]; /* to enforce alignment with inline data */
292 uint32_t decode[8]; /* to enforce alignment with inline data */
293 uint64_t offset_flags;
293 uint64_t offset_flags;
294 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
294 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
295 const char *c_node_id;
295 const char *c_node_id;
296 const char *data;
296 const char *data;
297 Py_ssize_t length = index_length(self);
297 Py_ssize_t length = index_length(self);
298 PyObject *entry;
298 PyObject *entry;
299
299
300 if (pos >= length) {
300 if (pos >= length) {
301 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
301 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
302 return NULL;
302 return NULL;
303 }
303 }
304
304
305 if (pos == length - 1) {
305 if (pos == length - 1) {
306 Py_INCREF(nullentry);
306 Py_INCREF(nullentry);
307 return nullentry;
307 return nullentry;
308 }
308 }
309
309
310 if (pos >= self->length - 1) {
310 if (pos >= self->length - 1) {
311 PyObject *obj;
311 PyObject *obj;
312 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
312 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
313 Py_INCREF(obj);
313 Py_INCREF(obj);
314 return obj;
314 return obj;
315 }
315 }
316
316
317 if (self->cache) {
317 if (self->cache) {
318 if (self->cache[pos]) {
318 if (self->cache[pos]) {
319 Py_INCREF(self->cache[pos]);
319 Py_INCREF(self->cache[pos]);
320 return self->cache[pos];
320 return self->cache[pos];
321 }
321 }
322 } else {
322 } else {
323 self->cache = calloc(self->raw_length, sizeof(PyObject *));
323 self->cache = calloc(self->raw_length, sizeof(PyObject *));
324 if (self->cache == NULL)
324 if (self->cache == NULL)
325 return PyErr_NoMemory();
325 return PyErr_NoMemory();
326 }
326 }
327
327
328 if (self->inlined && pos > 0) {
328 if (self->inlined && pos > 0) {
329 if (self->offsets == NULL) {
329 if (self->offsets == NULL) {
330 self->offsets = malloc(self->raw_length *
330 self->offsets = malloc(self->raw_length *
331 sizeof(*self->offsets));
331 sizeof(*self->offsets));
332 if (self->offsets == NULL)
332 if (self->offsets == NULL)
333 return PyErr_NoMemory();
333 return PyErr_NoMemory();
334 inline_scan(self, self->offsets);
334 inline_scan(self, self->offsets);
335 }
335 }
336 data = self->offsets[pos];
336 data = self->offsets[pos];
337 } else
337 } else
338 data = PyString_AS_STRING(self->data) + pos * 64;
338 data = PyString_AS_STRING(self->data) + pos * 64;
339
339
340 memcpy(decode, data, 8 * sizeof(uint32_t));
340 memcpy(decode, data, 8 * sizeof(uint32_t));
341
341
342 offset_flags = ntohl(decode[1]);
342 offset_flags = ntohl(decode[1]);
343 if (pos == 0) /* mask out version number for the first entry */
343 if (pos == 0) /* mask out version number for the first entry */
344 offset_flags &= 0xFFFF;
344 offset_flags &= 0xFFFF;
345 else {
345 else {
346 uint32_t offset_high = ntohl(decode[0]);
346 uint32_t offset_high = ntohl(decode[0]);
347 offset_flags |= ((uint64_t)offset_high) << 32;
347 offset_flags |= ((uint64_t)offset_high) << 32;
348 }
348 }
349
349
350 comp_len = ntohl(decode[2]);
350 comp_len = ntohl(decode[2]);
351 uncomp_len = ntohl(decode[3]);
351 uncomp_len = ntohl(decode[3]);
352 base_rev = ntohl(decode[4]);
352 base_rev = ntohl(decode[4]);
353 link_rev = ntohl(decode[5]);
353 link_rev = ntohl(decode[5]);
354 parent_1 = ntohl(decode[6]);
354 parent_1 = ntohl(decode[6]);
355 parent_2 = ntohl(decode[7]);
355 parent_2 = ntohl(decode[7]);
356 c_node_id = data + 32;
356 c_node_id = data + 32;
357
357
358 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
358 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
359 uncomp_len, base_rev, link_rev,
359 uncomp_len, base_rev, link_rev,
360 parent_1, parent_2, c_node_id, 20);
360 parent_1, parent_2, c_node_id, 20);
361
361
362 if (entry)
362 if (entry)
363 PyObject_GC_UnTrack(entry);
363 PyObject_GC_UnTrack(entry);
364
364
365 self->cache[pos] = entry;
365 self->cache[pos] = entry;
366 Py_INCREF(entry);
366 Py_INCREF(entry);
367
367
368 return entry;
368 return entry;
369 }
369 }
370
370
371 static PyObject *index_insert(indexObject *self, PyObject *args)
371 static PyObject *index_insert(indexObject *self, PyObject *args)
372 {
372 {
373 PyObject *obj, *node;
373 PyObject *obj, *node;
374 long offset;
374 long offset;
375 Py_ssize_t len;
375 Py_ssize_t len;
376
376
377 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
377 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
378 return NULL;
378 return NULL;
379
379
380 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
380 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
381 PyErr_SetString(PyExc_ValueError, "8-tuple required");
381 PyErr_SetString(PyExc_ValueError, "8-tuple required");
382 return NULL;
382 return NULL;
383 }
383 }
384
384
385 node = PyTuple_GET_ITEM(obj, 7);
385 node = PyTuple_GET_ITEM(obj, 7);
386 if (!PyString_Check(node) || PyString_GET_SIZE(node) != 20) {
386 if (!PyString_Check(node) || PyString_GET_SIZE(node) != 20) {
387 PyErr_SetString(PyExc_ValueError,
387 PyErr_SetString(PyExc_ValueError,
388 "20-byte hash required as last element");
388 "20-byte hash required as last element");
389 return NULL;
389 return NULL;
390 }
390 }
391
391
392 len = index_length(self);
392 len = index_length(self);
393
393
394 if (offset < 0)
394 if (offset < 0)
395 offset += len;
395 offset += len;
396
396
397 if (offset != len - 1) {
397 if (offset != len - 1) {
398 PyErr_SetString(PyExc_IndexError,
398 PyErr_SetString(PyExc_IndexError,
399 "insert only supported at index -1");
399 "insert only supported at index -1");
400 return NULL;
400 return NULL;
401 }
401 }
402
402
403 if (self->added == NULL) {
403 if (self->added == NULL) {
404 self->added = PyList_New(0);
404 self->added = PyList_New(0);
405 if (self->added == NULL)
405 if (self->added == NULL)
406 return NULL;
406 return NULL;
407 }
407 }
408
408
409 if (PyList_Append(self->added, obj) == -1)
409 if (PyList_Append(self->added, obj) == -1)
410 return NULL;
410 return NULL;
411
411
412 Py_RETURN_NONE;
412 Py_RETURN_NONE;
413 }
413 }
414
414
415 static void _index_clearcaches(indexObject *self)
416 {
417 if (self->cache) {
418 Py_ssize_t i;
419
420 for (i = 0; i < self->raw_length; i++) {
421 Py_XDECREF(self->cache[i]);
422 self->cache[i] = NULL;
423 }
424 free(self->cache);
425 self->cache = NULL;
426 }
427 if (self->offsets) {
428 free(self->offsets);
429 self->offsets = NULL;
430 }
431 }
432
433 static PyObject *index_clearcaches(indexObject *self)
434 {
435 _index_clearcaches(self);
436 Py_RETURN_NONE;
437 }
438
415 static int index_assign_subscript(indexObject *self, PyObject *item,
439 static int index_assign_subscript(indexObject *self, PyObject *item,
416 PyObject *value)
440 PyObject *value)
417 {
441 {
418 Py_ssize_t start, stop, step, slicelength;
442 Py_ssize_t start, stop, step, slicelength;
419 Py_ssize_t length = index_length(self);
443 Py_ssize_t length = index_length(self);
420
444
421 if (!PySlice_Check(item) || value != NULL) {
445 if (!PySlice_Check(item) || value != NULL) {
422 PyErr_SetString(PyExc_TypeError,
446 PyErr_SetString(PyExc_TypeError,
423 "revlog index only supports slice deletion");
447 "revlog index only supports slice deletion");
424 return -1;
448 return -1;
425 }
449 }
426
450
427 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
451 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
428 &start, &stop, &step, &slicelength) < 0)
452 &start, &stop, &step, &slicelength) < 0)
429 return -1;
453 return -1;
430
454
431 if (slicelength <= 0)
455 if (slicelength <= 0)
432 return 0;
456 return 0;
433
457
434 if ((step < 0 && start < stop) || (step > 0 && start > stop))
458 if ((step < 0 && start < stop) || (step > 0 && start > stop))
435 stop = start;
459 stop = start;
436
460
437 if (step < 0) {
461 if (step < 0) {
438 stop = start + 1;
462 stop = start + 1;
439 start = stop + step*(slicelength - 1) - 1;
463 start = stop + step*(slicelength - 1) - 1;
440 step = -step;
464 step = -step;
441 }
465 }
442
466
443 if (step != 1) {
467 if (step != 1) {
444 PyErr_SetString(PyExc_ValueError,
468 PyErr_SetString(PyExc_ValueError,
445 "revlog index delete requires step size of 1");
469 "revlog index delete requires step size of 1");
446 return -1;
470 return -1;
447 }
471 }
448
472
449 if (stop != length - 1) {
473 if (stop != length - 1) {
450 PyErr_SetString(PyExc_IndexError,
474 PyErr_SetString(PyExc_IndexError,
451 "revlog index deletion indices are invalid");
475 "revlog index deletion indices are invalid");
452 return -1;
476 return -1;
453 }
477 }
454
478
455 if (start < self->length) {
479 if (start < self->length) {
456 self->length = start + 1;
480 self->length = start + 1;
457 if (self->added) {
481 if (self->added) {
458 Py_DECREF(self->added);
482 Py_DECREF(self->added);
459 self->added = NULL;
483 self->added = NULL;
460 }
484 }
461 return 0;
485 return 0;
462 }
486 }
463
487
464 return PyList_SetSlice(self->added, start - self->length + 1,
488 return PyList_SetSlice(self->added, start - self->length + 1,
465 PyList_GET_SIZE(self->added),
489 PyList_GET_SIZE(self->added),
466 NULL);
490 NULL);
467 }
491 }
468
492
469 static long inline_scan(indexObject *self, const char **offsets)
493 static long inline_scan(indexObject *self, const char **offsets)
470 {
494 {
471 const char *data = PyString_AS_STRING(self->data);
495 const char *data = PyString_AS_STRING(self->data);
472 const char *end = data + PyString_GET_SIZE(self->data);
496 const char *end = data + PyString_GET_SIZE(self->data);
473 const long hdrsize = 64;
497 const long hdrsize = 64;
474 long incr = hdrsize;
498 long incr = hdrsize;
475 Py_ssize_t len = 0;
499 Py_ssize_t len = 0;
476
500
477 while (data + hdrsize <= end) {
501 while (data + hdrsize <= end) {
478 uint32_t comp_len;
502 uint32_t comp_len;
479 const char *old_data;
503 const char *old_data;
480 /* 3rd element of header is length of compressed inline data */
504 /* 3rd element of header is length of compressed inline data */
481 memcpy(&comp_len, data + 8, sizeof(uint32_t));
505 memcpy(&comp_len, data + 8, sizeof(uint32_t));
482 incr = hdrsize + ntohl(comp_len);
506 incr = hdrsize + ntohl(comp_len);
483 if (incr < hdrsize)
507 if (incr < hdrsize)
484 break;
508 break;
485 if (offsets)
509 if (offsets)
486 offsets[len] = data;
510 offsets[len] = data;
487 len++;
511 len++;
488 old_data = data;
512 old_data = data;
489 data += incr;
513 data += incr;
490 if (data <= old_data)
514 if (data <= old_data)
491 break;
515 break;
492 }
516 }
493
517
494 if (data != end && data + hdrsize != end) {
518 if (data != end && data + hdrsize != end) {
495 if (!PyErr_Occurred())
519 if (!PyErr_Occurred())
496 PyErr_SetString(PyExc_ValueError, "corrupt index file");
520 PyErr_SetString(PyExc_ValueError, "corrupt index file");
497 return -1;
521 return -1;
498 }
522 }
499
523
500 return len;
524 return len;
501 }
525 }
502
526
503 static int index_real_init(indexObject *self, const char *data, int size,
527 static int index_real_init(indexObject *self, const char *data, int size,
504 PyObject *inlined_obj, PyObject *data_obj)
528 PyObject *inlined_obj, PyObject *data_obj)
505 {
529 {
506 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
530 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
507 self->data = data_obj;
531 self->data = data_obj;
508 self->cache = NULL;
532 self->cache = NULL;
509
533
510 self->added = NULL;
534 self->added = NULL;
511 self->offsets = NULL;
535 self->offsets = NULL;
512 Py_INCREF(self->data);
536 Py_INCREF(self->data);
513
537
514 if (self->inlined) {
538 if (self->inlined) {
515 long len = inline_scan(self, NULL);
539 long len = inline_scan(self, NULL);
516 if (len == -1)
540 if (len == -1)
517 goto bail;
541 goto bail;
518 self->raw_length = len;
542 self->raw_length = len;
519 self->length = len + 1;
543 self->length = len + 1;
520 } else {
544 } else {
521 if (size % 64) {
545 if (size % 64) {
522 PyErr_SetString(PyExc_ValueError, "corrupt index file");
546 PyErr_SetString(PyExc_ValueError, "corrupt index file");
523 goto bail;
547 goto bail;
524 }
548 }
525 self->raw_length = size / 64;
549 self->raw_length = size / 64;
526 self->length = self->raw_length + 1;
550 self->length = self->raw_length + 1;
527 }
551 }
528
552
529 return 0;
553 return 0;
530 bail:
554 bail:
531 return -1;
555 return -1;
532 }
556 }
533
557
534 static int index_init(indexObject *self, PyObject *args, PyObject *kwds)
558 static int index_init(indexObject *self, PyObject *args, PyObject *kwds)
535 {
559 {
536 const char *data;
560 const char *data;
537 int size;
561 int size;
538 PyObject *inlined_obj;
562 PyObject *inlined_obj;
539
563
540 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
564 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
541 return -1;
565 return -1;
542
566
543 return index_real_init(self, data, size, inlined_obj,
567 return index_real_init(self, data, size, inlined_obj,
544 PyTuple_GET_ITEM(args, 0));
568 PyTuple_GET_ITEM(args, 0));
545 }
569 }
546
570
547 static void index_dealloc(indexObject *self)
571 static void index_dealloc(indexObject *self)
548 {
572 {
573 _index_clearcaches(self);
549 Py_DECREF(self->data);
574 Py_DECREF(self->data);
550 if (self->cache) {
551 Py_ssize_t i;
552
553 for (i = 0; i < self->raw_length; i++)
554 Py_XDECREF(self->cache[i]);
555 }
556 Py_XDECREF(self->added);
575 Py_XDECREF(self->added);
557 free(self->offsets);
558 PyObject_Del(self);
576 PyObject_Del(self);
559 }
577 }
560
578
561 static PySequenceMethods index_sequence_methods = {
579 static PySequenceMethods index_sequence_methods = {
562 (lenfunc)index_length, /* sq_length */
580 (lenfunc)index_length, /* sq_length */
563 0, /* sq_concat */
581 0, /* sq_concat */
564 0, /* sq_repeat */
582 0, /* sq_repeat */
565 (ssizeargfunc)index_get, /* sq_item */
583 (ssizeargfunc)index_get, /* sq_item */
566 };
584 };
567
585
568 static PyMappingMethods index_mapping_methods = {
586 static PyMappingMethods index_mapping_methods = {
569 (lenfunc)index_length, /* mp_length */
587 (lenfunc)index_length, /* mp_length */
570 NULL, /* mp_subscript */
588 NULL, /* mp_subscript */
571 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
589 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
572 };
590 };
573
591
574 static PyMethodDef index_methods[] = {
592 static PyMethodDef index_methods[] = {
593 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
594 "clear the index caches"},
575 {"insert", (PyCFunction)index_insert, METH_VARARGS,
595 {"insert", (PyCFunction)index_insert, METH_VARARGS,
576 "insert an index entry"},
596 "insert an index entry"},
577 {NULL} /* Sentinel */
597 {NULL} /* Sentinel */
578 };
598 };
579
599
580 static PyTypeObject indexType = {
600 static PyTypeObject indexType = {
581 PyObject_HEAD_INIT(NULL)
601 PyObject_HEAD_INIT(NULL)
582 0, /* ob_size */
602 0, /* ob_size */
583 "parsers.index", /* tp_name */
603 "parsers.index", /* tp_name */
584 sizeof(indexObject), /* tp_basicsize */
604 sizeof(indexObject), /* tp_basicsize */
585 0, /* tp_itemsize */
605 0, /* tp_itemsize */
586 (destructor)index_dealloc, /* tp_dealloc */
606 (destructor)index_dealloc, /* tp_dealloc */
587 0, /* tp_print */
607 0, /* tp_print */
588 0, /* tp_getattr */
608 0, /* tp_getattr */
589 0, /* tp_setattr */
609 0, /* tp_setattr */
590 0, /* tp_compare */
610 0, /* tp_compare */
591 0, /* tp_repr */
611 0, /* tp_repr */
592 0, /* tp_as_number */
612 0, /* tp_as_number */
593 &index_sequence_methods, /* tp_as_sequence */
613 &index_sequence_methods, /* tp_as_sequence */
594 &index_mapping_methods, /* tp_as_mapping */
614 &index_mapping_methods, /* tp_as_mapping */
595 0, /* tp_hash */
615 0, /* tp_hash */
596 0, /* tp_call */
616 0, /* tp_call */
597 0, /* tp_str */
617 0, /* tp_str */
598 0, /* tp_getattro */
618 0, /* tp_getattro */
599 0, /* tp_setattro */
619 0, /* tp_setattro */
600 0, /* tp_as_buffer */
620 0, /* tp_as_buffer */
601 Py_TPFLAGS_DEFAULT, /* tp_flags */
621 Py_TPFLAGS_DEFAULT, /* tp_flags */
602 "revlog index", /* tp_doc */
622 "revlog index", /* tp_doc */
603 0, /* tp_traverse */
623 0, /* tp_traverse */
604 0, /* tp_clear */
624 0, /* tp_clear */
605 0, /* tp_richcompare */
625 0, /* tp_richcompare */
606 0, /* tp_weaklistoffset */
626 0, /* tp_weaklistoffset */
607 0, /* tp_iter */
627 0, /* tp_iter */
608 0, /* tp_iternext */
628 0, /* tp_iternext */
609 index_methods, /* tp_methods */
629 index_methods, /* tp_methods */
610 0, /* tp_members */
630 0, /* tp_members */
611 0, /* tp_getset */
631 0, /* tp_getset */
612 0, /* tp_base */
632 0, /* tp_base */
613 0, /* tp_dict */
633 0, /* tp_dict */
614 0, /* tp_descr_get */
634 0, /* tp_descr_get */
615 0, /* tp_descr_set */
635 0, /* tp_descr_set */
616 0, /* tp_dictoffset */
636 0, /* tp_dictoffset */
617 (initproc)index_init, /* tp_init */
637 (initproc)index_init, /* tp_init */
618 0, /* tp_alloc */
638 0, /* tp_alloc */
619 PyType_GenericNew, /* tp_new */
639 PyType_GenericNew, /* tp_new */
620 };
640 };
621
641
622 /*
642 /*
623 * returns a tuple of the form (index, None, cache) with elements as
643 * returns a tuple of the form (index, None, cache) with elements as
624 * follows:
644 * follows:
625 *
645 *
626 * index: an index object that lazily parses the RevlogNG records
646 * index: an index object that lazily parses the RevlogNG records
627 * cache: if data is inlined, a tuple (index_file_content, 0), else None
647 * cache: if data is inlined, a tuple (index_file_content, 0), else None
628 *
648 *
629 * added complications are for backwards compatibility
649 * added complications are for backwards compatibility
630 */
650 */
631 static PyObject *parse_index2(PyObject *self, PyObject *args)
651 static PyObject *parse_index2(PyObject *self, PyObject *args)
632 {
652 {
633 const char *data;
653 const char *data;
634 int size, ret;
654 int size, ret;
635 PyObject *inlined_obj, *tuple = NULL, *cache = NULL;
655 PyObject *inlined_obj, *tuple = NULL, *cache = NULL;
636 indexObject *idx;
656 indexObject *idx;
637
657
638 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
658 if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
639 return NULL;
659 return NULL;
640
660
641 idx = PyObject_New(indexObject, &indexType);
661 idx = PyObject_New(indexObject, &indexType);
642
662
643 if (idx == NULL)
663 if (idx == NULL)
644 goto bail;
664 goto bail;
645
665
646 ret = index_real_init(idx, data, size, inlined_obj,
666 ret = index_real_init(idx, data, size, inlined_obj,
647 PyTuple_GET_ITEM(args, 0));
667 PyTuple_GET_ITEM(args, 0));
648 if (ret)
668 if (ret)
649 goto bail;
669 goto bail;
650
670
651 if (idx->inlined) {
671 if (idx->inlined) {
652 Py_INCREF(idx->data);
672 Py_INCREF(idx->data);
653 cache = Py_BuildValue("iO", 0, idx->data);
673 cache = Py_BuildValue("iO", 0, idx->data);
654 if (cache == NULL)
674 if (cache == NULL)
655 goto bail;
675 goto bail;
656 } else {
676 } else {
657 cache = Py_None;
677 cache = Py_None;
658 Py_INCREF(cache);
678 Py_INCREF(cache);
659 }
679 }
660
680
661 tuple = Py_BuildValue("NN", idx, cache);
681 tuple = Py_BuildValue("NN", idx, cache);
662 if (!tuple)
682 if (!tuple)
663 goto bail;
683 goto bail;
664 return tuple;
684 return tuple;
665
685
666 bail:
686 bail:
667 Py_XDECREF(idx);
687 Py_XDECREF(idx);
668 Py_XDECREF(cache);
688 Py_XDECREF(cache);
669 Py_XDECREF(tuple);
689 Py_XDECREF(tuple);
670 return NULL;
690 return NULL;
671 }
691 }
672
692
673 static char parsers_doc[] = "Efficient content parsing.";
693 static char parsers_doc[] = "Efficient content parsing.";
674
694
675 static PyMethodDef methods[] = {
695 static PyMethodDef methods[] = {
676 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
696 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
677 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
697 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
678 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
698 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
679 {NULL, NULL}
699 {NULL, NULL}
680 };
700 };
681
701
682 static void module_init(PyObject *mod)
702 static void module_init(PyObject *mod)
683 {
703 {
684 static const char nullid[20];
704 static const char nullid[20];
685
705
686 if (PyType_Ready(&indexType) < 0)
706 if (PyType_Ready(&indexType) < 0)
687 return;
707 return;
688 Py_INCREF(&indexType);
708 Py_INCREF(&indexType);
689
709
690 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
710 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
691
711
692 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
712 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
693 -1, -1, -1, -1, nullid, 20);
713 -1, -1, -1, -1, nullid, 20);
694 if (nullentry)
714 if (nullentry)
695 PyObject_GC_UnTrack(nullentry);
715 PyObject_GC_UnTrack(nullentry);
696 }
716 }
697
717
698 #ifdef IS_PY3K
718 #ifdef IS_PY3K
699 static struct PyModuleDef parsers_module = {
719 static struct PyModuleDef parsers_module = {
700 PyModuleDef_HEAD_INIT,
720 PyModuleDef_HEAD_INIT,
701 "parsers",
721 "parsers",
702 parsers_doc,
722 parsers_doc,
703 -1,
723 -1,
704 methods
724 methods
705 };
725 };
706
726
707 PyMODINIT_FUNC PyInit_parsers(void)
727 PyMODINIT_FUNC PyInit_parsers(void)
708 {
728 {
709 PyObject *mod = PyModule_Create(&parsers_module);
729 PyObject *mod = PyModule_Create(&parsers_module);
710 module_init(mod);
730 module_init(mod);
711 return mod;
731 return mod;
712 }
732 }
713 #else
733 #else
714 PyMODINIT_FUNC initparsers(void)
734 PyMODINIT_FUNC initparsers(void)
715 {
735 {
716 PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc);
736 PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc);
717 module_init(mod);
737 module_init(mod);
718 }
738 }
719 #endif
739 #endif
720
740
General Comments 0
You need to be logged in to leave comments. Login now