##// END OF EJS Templates
merge with stable
Yuya Nishihara -
r45078:090a1a78 merge default
parent child Browse files
Show More
@@ -1,2917 +1,2918 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 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <assert.h>
12 #include <assert.h>
13 #include <ctype.h>
13 #include <ctype.h>
14 #include <limits.h>
14 #include <limits.h>
15 #include <stddef.h>
15 #include <stddef.h>
16 #include <stdlib.h>
16 #include <stdlib.h>
17 #include <string.h>
17 #include <string.h>
18
18
19 #include "bitmanipulation.h"
19 #include "bitmanipulation.h"
20 #include "charencode.h"
20 #include "charencode.h"
21 #include "revlog.h"
21 #include "revlog.h"
22 #include "util.h"
22 #include "util.h"
23
23
24 #ifdef IS_PY3K
24 #ifdef IS_PY3K
25 /* The mapping of Python types is meant to be temporary to get Python
25 /* The mapping of Python types is meant to be temporary to get Python
26 * 3 to compile. We should remove this once Python 3 support is fully
26 * 3 to compile. We should remove this once Python 3 support is fully
27 * supported and proper types are used in the extensions themselves. */
27 * supported and proper types are used in the extensions themselves. */
28 #define PyInt_Check PyLong_Check
28 #define PyInt_Check PyLong_Check
29 #define PyInt_FromLong PyLong_FromLong
29 #define PyInt_FromLong PyLong_FromLong
30 #define PyInt_FromSsize_t PyLong_FromSsize_t
30 #define PyInt_FromSsize_t PyLong_FromSsize_t
31 #define PyInt_AsLong PyLong_AsLong
31 #define PyInt_AsLong PyLong_AsLong
32 #endif
32 #endif
33
33
34 typedef struct indexObjectStruct indexObject;
34 typedef struct indexObjectStruct indexObject;
35
35
36 typedef struct {
36 typedef struct {
37 int children[16];
37 int children[16];
38 } nodetreenode;
38 } nodetreenode;
39
39
40 typedef struct {
40 typedef struct {
41 int abi_version;
41 int abi_version;
42 Py_ssize_t (*index_length)(const indexObject *);
42 Py_ssize_t (*index_length)(const indexObject *);
43 const char *(*index_node)(indexObject *, Py_ssize_t);
43 const char *(*index_node)(indexObject *, Py_ssize_t);
44 int (*index_parents)(PyObject *, int, int *);
44 int (*index_parents)(PyObject *, int, int *);
45 } Revlog_CAPI;
45 } Revlog_CAPI;
46
46
47 /*
47 /*
48 * A base-16 trie for fast node->rev mapping.
48 * A base-16 trie for fast node->rev mapping.
49 *
49 *
50 * Positive value is index of the next node in the trie
50 * Positive value is index of the next node in the trie
51 * Negative value is a leaf: -(rev + 2)
51 * Negative value is a leaf: -(rev + 2)
52 * Zero is empty
52 * Zero is empty
53 */
53 */
54 typedef struct {
54 typedef struct {
55 indexObject *index;
55 indexObject *index;
56 nodetreenode *nodes;
56 nodetreenode *nodes;
57 unsigned length; /* # nodes in use */
57 unsigned length; /* # nodes in use */
58 unsigned capacity; /* # nodes allocated */
58 unsigned capacity; /* # nodes allocated */
59 int depth; /* maximum depth of tree */
59 int depth; /* maximum depth of tree */
60 int splits; /* # splits performed */
60 int splits; /* # splits performed */
61 } nodetree;
61 } nodetree;
62
62
63 typedef struct {
63 typedef struct {
64 PyObject_HEAD /* ; */
64 PyObject_HEAD /* ; */
65 nodetree nt;
65 nodetree nt;
66 } nodetreeObject;
66 } nodetreeObject;
67
67
68 /*
68 /*
69 * This class has two behaviors.
69 * This class has two behaviors.
70 *
70 *
71 * When used in a list-like way (with integer keys), we decode an
71 * When used in a list-like way (with integer keys), we decode an
72 * entry in a RevlogNG index file on demand. We have limited support for
72 * entry in a RevlogNG index file on demand. We have limited support for
73 * integer-keyed insert and delete, only at elements right before the
73 * integer-keyed insert and delete, only at elements right before the
74 * end.
74 * end.
75 *
75 *
76 * With string keys, we lazily perform a reverse mapping from node to
76 * With string keys, we lazily perform a reverse mapping from node to
77 * rev, using a base-16 trie.
77 * rev, using a base-16 trie.
78 */
78 */
79 struct indexObjectStruct {
79 struct indexObjectStruct {
80 PyObject_HEAD
80 PyObject_HEAD
81 /* Type-specific fields go here. */
81 /* Type-specific fields go here. */
82 PyObject *data; /* raw bytes of index */
82 PyObject *data; /* raw bytes of index */
83 Py_buffer buf; /* buffer of data */
83 Py_buffer buf; /* buffer of data */
84 PyObject **cache; /* cached tuples */
84 PyObject **cache; /* cached tuples */
85 const char **offsets; /* populated on demand */
85 const char **offsets; /* populated on demand */
86 Py_ssize_t raw_length; /* original number of elements */
86 Py_ssize_t raw_length; /* original number of elements */
87 Py_ssize_t length; /* current number of elements */
87 Py_ssize_t length; /* current number of elements */
88 PyObject *added; /* populated on demand */
88 PyObject *added; /* populated on demand */
89 PyObject *headrevs; /* cache, invalidated on changes */
89 PyObject *headrevs; /* cache, invalidated on changes */
90 PyObject *filteredrevs; /* filtered revs set */
90 PyObject *filteredrevs; /* filtered revs set */
91 nodetree nt; /* base-16 trie */
91 nodetree nt; /* base-16 trie */
92 int ntinitialized; /* 0 or 1 */
92 int ntinitialized; /* 0 or 1 */
93 int ntrev; /* last rev scanned */
93 int ntrev; /* last rev scanned */
94 int ntlookups; /* # lookups */
94 int ntlookups; /* # lookups */
95 int ntmisses; /* # lookups that miss the cache */
95 int ntmisses; /* # lookups that miss the cache */
96 int inlined;
96 int inlined;
97 };
97 };
98
98
99 static Py_ssize_t index_length(const indexObject *self)
99 static Py_ssize_t index_length(const indexObject *self)
100 {
100 {
101 if (self->added == NULL)
101 if (self->added == NULL)
102 return self->length;
102 return self->length;
103 return self->length + PyList_GET_SIZE(self->added);
103 return self->length + PyList_GET_SIZE(self->added);
104 }
104 }
105
105
106 static PyObject *nullentry = NULL;
106 static PyObject *nullentry = NULL;
107 static const char nullid[20] = {0};
107 static const char nullid[20] = {0};
108 static const Py_ssize_t nullrev = -1;
108 static const Py_ssize_t nullrev = -1;
109
109
110 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
110 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
111
111
112 #if LONG_MAX == 0x7fffffffL
112 #if LONG_MAX == 0x7fffffffL
113 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
113 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
114 #else
114 #else
115 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
115 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
116 #endif
116 #endif
117
117
118 /* A RevlogNG v1 index entry is 64 bytes long. */
118 /* A RevlogNG v1 index entry is 64 bytes long. */
119 static const long v1_hdrsize = 64;
119 static const long v1_hdrsize = 64;
120
120
121 static void raise_revlog_error(void)
121 static void raise_revlog_error(void)
122 {
122 {
123 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
123 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
124
124
125 mod = PyImport_ImportModule("mercurial.error");
125 mod = PyImport_ImportModule("mercurial.error");
126 if (mod == NULL) {
126 if (mod == NULL) {
127 goto cleanup;
127 goto cleanup;
128 }
128 }
129
129
130 dict = PyModule_GetDict(mod);
130 dict = PyModule_GetDict(mod);
131 if (dict == NULL) {
131 if (dict == NULL) {
132 goto cleanup;
132 goto cleanup;
133 }
133 }
134 Py_INCREF(dict);
134 Py_INCREF(dict);
135
135
136 errclass = PyDict_GetItemString(dict, "RevlogError");
136 errclass = PyDict_GetItemString(dict, "RevlogError");
137 if (errclass == NULL) {
137 if (errclass == NULL) {
138 PyErr_SetString(PyExc_SystemError,
138 PyErr_SetString(PyExc_SystemError,
139 "could not find RevlogError");
139 "could not find RevlogError");
140 goto cleanup;
140 goto cleanup;
141 }
141 }
142
142
143 /* value of exception is ignored by callers */
143 /* value of exception is ignored by callers */
144 PyErr_SetString(errclass, "RevlogError");
144 PyErr_SetString(errclass, "RevlogError");
145
145
146 cleanup:
146 cleanup:
147 Py_XDECREF(dict);
147 Py_XDECREF(dict);
148 Py_XDECREF(mod);
148 Py_XDECREF(mod);
149 }
149 }
150
150
151 /*
151 /*
152 * Return a pointer to the beginning of a RevlogNG record.
152 * Return a pointer to the beginning of a RevlogNG record.
153 */
153 */
154 static const char *index_deref(indexObject *self, Py_ssize_t pos)
154 static const char *index_deref(indexObject *self, Py_ssize_t pos)
155 {
155 {
156 if (self->inlined && pos > 0) {
156 if (self->inlined && pos > 0) {
157 if (self->offsets == NULL) {
157 if (self->offsets == NULL) {
158 Py_ssize_t ret;
158 self->offsets = PyMem_Malloc(self->raw_length *
159 self->offsets = PyMem_Malloc(self->raw_length *
159 sizeof(*self->offsets));
160 sizeof(*self->offsets));
160 if (self->offsets == NULL)
161 if (self->offsets == NULL)
161 return (const char *)PyErr_NoMemory();
162 return (const char *)PyErr_NoMemory();
162 Py_ssize_t ret = inline_scan(self, self->offsets);
163 ret = inline_scan(self, self->offsets);
163 if (ret == -1) {
164 if (ret == -1) {
164 return NULL;
165 return NULL;
165 };
166 };
166 }
167 }
167 return self->offsets[pos];
168 return self->offsets[pos];
168 }
169 }
169
170
170 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
171 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
171 }
172 }
172
173
173 /*
174 /*
174 * Get parents of the given rev.
175 * Get parents of the given rev.
175 *
176 *
176 * The specified rev must be valid and must not be nullrev. A returned
177 * The specified rev must be valid and must not be nullrev. A returned
177 * parent revision may be nullrev, but is guaranteed to be in valid range.
178 * parent revision may be nullrev, but is guaranteed to be in valid range.
178 */
179 */
179 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
180 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
180 int maxrev)
181 int maxrev)
181 {
182 {
182 if (rev >= self->length) {
183 if (rev >= self->length) {
183 long tmp;
184 long tmp;
184 PyObject *tuple =
185 PyObject *tuple =
185 PyList_GET_ITEM(self->added, rev - self->length);
186 PyList_GET_ITEM(self->added, rev - self->length);
186 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
187 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
187 return -1;
188 return -1;
188 }
189 }
189 ps[0] = (int)tmp;
190 ps[0] = (int)tmp;
190 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 6), &tmp)) {
191 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 6), &tmp)) {
191 return -1;
192 return -1;
192 }
193 }
193 ps[1] = (int)tmp;
194 ps[1] = (int)tmp;
194 } else {
195 } else {
195 const char *data = index_deref(self, rev);
196 const char *data = index_deref(self, rev);
196 ps[0] = getbe32(data + 24);
197 ps[0] = getbe32(data + 24);
197 ps[1] = getbe32(data + 28);
198 ps[1] = getbe32(data + 28);
198 }
199 }
199 /* If index file is corrupted, ps[] may point to invalid revisions. So
200 /* If index file is corrupted, ps[] may point to invalid revisions. So
200 * there is a risk of buffer overflow to trust them unconditionally. */
201 * there is a risk of buffer overflow to trust them unconditionally. */
201 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
202 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
202 PyErr_SetString(PyExc_ValueError, "parent out of range");
203 PyErr_SetString(PyExc_ValueError, "parent out of range");
203 return -1;
204 return -1;
204 }
205 }
205 return 0;
206 return 0;
206 }
207 }
207
208
208 /*
209 /*
209 * Get parents of the given rev.
210 * Get parents of the given rev.
210 *
211 *
211 * If the specified rev is out of range, IndexError will be raised. If the
212 * If the specified rev is out of range, IndexError will be raised. If the
212 * revlog entry is corrupted, ValueError may be raised.
213 * revlog entry is corrupted, ValueError may be raised.
213 *
214 *
214 * Returns 0 on success or -1 on failure.
215 * Returns 0 on success or -1 on failure.
215 */
216 */
216 static int HgRevlogIndex_GetParents(PyObject *op, int rev, int *ps)
217 static int HgRevlogIndex_GetParents(PyObject *op, int rev, int *ps)
217 {
218 {
218 int tiprev;
219 int tiprev;
219 if (!op || !HgRevlogIndex_Check(op) || !ps) {
220 if (!op || !HgRevlogIndex_Check(op) || !ps) {
220 PyErr_BadInternalCall();
221 PyErr_BadInternalCall();
221 return -1;
222 return -1;
222 }
223 }
223 tiprev = (int)index_length((indexObject *)op) - 1;
224 tiprev = (int)index_length((indexObject *)op) - 1;
224 if (rev < -1 || rev > tiprev) {
225 if (rev < -1 || rev > tiprev) {
225 PyErr_Format(PyExc_IndexError, "rev out of range: %d", rev);
226 PyErr_Format(PyExc_IndexError, "rev out of range: %d", rev);
226 return -1;
227 return -1;
227 } else if (rev == -1) {
228 } else if (rev == -1) {
228 ps[0] = ps[1] = -1;
229 ps[0] = ps[1] = -1;
229 return 0;
230 return 0;
230 } else {
231 } else {
231 return index_get_parents((indexObject *)op, rev, ps, tiprev);
232 return index_get_parents((indexObject *)op, rev, ps, tiprev);
232 }
233 }
233 }
234 }
234
235
235 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
236 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
236 {
237 {
237 uint64_t offset;
238 uint64_t offset;
238 if (rev == nullrev) {
239 if (rev == nullrev) {
239 return 0;
240 return 0;
240 }
241 }
241 if (rev >= self->length) {
242 if (rev >= self->length) {
242 PyObject *tuple;
243 PyObject *tuple;
243 PyObject *pylong;
244 PyObject *pylong;
244 PY_LONG_LONG tmp;
245 PY_LONG_LONG tmp;
245 tuple = PyList_GET_ITEM(self->added, rev - self->length);
246 tuple = PyList_GET_ITEM(self->added, rev - self->length);
246 pylong = PyTuple_GET_ITEM(tuple, 0);
247 pylong = PyTuple_GET_ITEM(tuple, 0);
247 tmp = PyLong_AsLongLong(pylong);
248 tmp = PyLong_AsLongLong(pylong);
248 if (tmp == -1 && PyErr_Occurred()) {
249 if (tmp == -1 && PyErr_Occurred()) {
249 return -1;
250 return -1;
250 }
251 }
251 if (tmp < 0) {
252 if (tmp < 0) {
252 PyErr_Format(PyExc_OverflowError,
253 PyErr_Format(PyExc_OverflowError,
253 "revlog entry size out of bound (%lld)",
254 "revlog entry size out of bound (%lld)",
254 (long long)tmp);
255 (long long)tmp);
255 return -1;
256 return -1;
256 }
257 }
257 offset = (uint64_t)tmp;
258 offset = (uint64_t)tmp;
258 } else {
259 } else {
259 const char *data = index_deref(self, rev);
260 const char *data = index_deref(self, rev);
260 offset = getbe32(data + 4);
261 offset = getbe32(data + 4);
261 if (rev == 0) {
262 if (rev == 0) {
262 /* mask out version number for the first entry */
263 /* mask out version number for the first entry */
263 offset &= 0xFFFF;
264 offset &= 0xFFFF;
264 } else {
265 } else {
265 uint32_t offset_high = getbe32(data);
266 uint32_t offset_high = getbe32(data);
266 offset |= ((uint64_t)offset_high) << 32;
267 offset |= ((uint64_t)offset_high) << 32;
267 }
268 }
268 }
269 }
269 return (int64_t)(offset >> 16);
270 return (int64_t)(offset >> 16);
270 }
271 }
271
272
272 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
273 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
273 {
274 {
274 if (rev == nullrev) {
275 if (rev == nullrev) {
275 return 0;
276 return 0;
276 }
277 }
277 if (rev >= self->length) {
278 if (rev >= self->length) {
278 PyObject *tuple;
279 PyObject *tuple;
279 PyObject *pylong;
280 PyObject *pylong;
280 long ret;
281 long ret;
281 tuple = PyList_GET_ITEM(self->added, rev - self->length);
282 tuple = PyList_GET_ITEM(self->added, rev - self->length);
282 pylong = PyTuple_GET_ITEM(tuple, 1);
283 pylong = PyTuple_GET_ITEM(tuple, 1);
283 ret = PyInt_AsLong(pylong);
284 ret = PyInt_AsLong(pylong);
284 if (ret == -1 && PyErr_Occurred()) {
285 if (ret == -1 && PyErr_Occurred()) {
285 return -1;
286 return -1;
286 }
287 }
287 if (ret < 0 || ret > (long)INT_MAX) {
288 if (ret < 0 || ret > (long)INT_MAX) {
288 PyErr_Format(PyExc_OverflowError,
289 PyErr_Format(PyExc_OverflowError,
289 "revlog entry size out of bound (%ld)",
290 "revlog entry size out of bound (%ld)",
290 ret);
291 ret);
291 return -1;
292 return -1;
292 }
293 }
293 return (int)ret;
294 return (int)ret;
294 } else {
295 } else {
295 const char *data = index_deref(self, rev);
296 const char *data = index_deref(self, rev);
296 int tmp = (int)getbe32(data + 8);
297 int tmp = (int)getbe32(data + 8);
297 if (tmp < 0) {
298 if (tmp < 0) {
298 PyErr_Format(PyExc_OverflowError,
299 PyErr_Format(PyExc_OverflowError,
299 "revlog entry size out of bound (%d)",
300 "revlog entry size out of bound (%d)",
300 tmp);
301 tmp);
301 return -1;
302 return -1;
302 }
303 }
303 return tmp;
304 return tmp;
304 }
305 }
305 }
306 }
306
307
307 /*
308 /*
308 * RevlogNG format (all in big endian, data may be inlined):
309 * RevlogNG format (all in big endian, data may be inlined):
309 * 6 bytes: offset
310 * 6 bytes: offset
310 * 2 bytes: flags
311 * 2 bytes: flags
311 * 4 bytes: compressed length
312 * 4 bytes: compressed length
312 * 4 bytes: uncompressed length
313 * 4 bytes: uncompressed length
313 * 4 bytes: base revision
314 * 4 bytes: base revision
314 * 4 bytes: link revision
315 * 4 bytes: link revision
315 * 4 bytes: parent 1 revision
316 * 4 bytes: parent 1 revision
316 * 4 bytes: parent 2 revision
317 * 4 bytes: parent 2 revision
317 * 32 bytes: nodeid (only 20 bytes used)
318 * 32 bytes: nodeid (only 20 bytes used)
318 */
319 */
319 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
320 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
320 {
321 {
321 uint64_t offset_flags;
322 uint64_t offset_flags;
322 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
323 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
323 const char *c_node_id;
324 const char *c_node_id;
324 const char *data;
325 const char *data;
325 Py_ssize_t length = index_length(self);
326 Py_ssize_t length = index_length(self);
326 PyObject *entry;
327 PyObject *entry;
327
328
328 if (pos == nullrev) {
329 if (pos == nullrev) {
329 Py_INCREF(nullentry);
330 Py_INCREF(nullentry);
330 return nullentry;
331 return nullentry;
331 }
332 }
332
333
333 if (pos < 0 || pos >= length) {
334 if (pos < 0 || pos >= length) {
334 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
335 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
335 return NULL;
336 return NULL;
336 }
337 }
337
338
338 if (pos >= self->length) {
339 if (pos >= self->length) {
339 PyObject *obj;
340 PyObject *obj;
340 obj = PyList_GET_ITEM(self->added, pos - self->length);
341 obj = PyList_GET_ITEM(self->added, pos - self->length);
341 Py_INCREF(obj);
342 Py_INCREF(obj);
342 return obj;
343 return obj;
343 }
344 }
344
345
345 if (self->cache) {
346 if (self->cache) {
346 if (self->cache[pos]) {
347 if (self->cache[pos]) {
347 Py_INCREF(self->cache[pos]);
348 Py_INCREF(self->cache[pos]);
348 return self->cache[pos];
349 return self->cache[pos];
349 }
350 }
350 } else {
351 } else {
351 self->cache = calloc(self->raw_length, sizeof(PyObject *));
352 self->cache = calloc(self->raw_length, sizeof(PyObject *));
352 if (self->cache == NULL)
353 if (self->cache == NULL)
353 return PyErr_NoMemory();
354 return PyErr_NoMemory();
354 }
355 }
355
356
356 data = index_deref(self, pos);
357 data = index_deref(self, pos);
357 if (data == NULL)
358 if (data == NULL)
358 return NULL;
359 return NULL;
359
360
360 offset_flags = getbe32(data + 4);
361 offset_flags = getbe32(data + 4);
361 if (pos == 0) /* mask out version number for the first entry */
362 if (pos == 0) /* mask out version number for the first entry */
362 offset_flags &= 0xFFFF;
363 offset_flags &= 0xFFFF;
363 else {
364 else {
364 uint32_t offset_high = getbe32(data);
365 uint32_t offset_high = getbe32(data);
365 offset_flags |= ((uint64_t)offset_high) << 32;
366 offset_flags |= ((uint64_t)offset_high) << 32;
366 }
367 }
367
368
368 comp_len = getbe32(data + 8);
369 comp_len = getbe32(data + 8);
369 uncomp_len = getbe32(data + 12);
370 uncomp_len = getbe32(data + 12);
370 base_rev = getbe32(data + 16);
371 base_rev = getbe32(data + 16);
371 link_rev = getbe32(data + 20);
372 link_rev = getbe32(data + 20);
372 parent_1 = getbe32(data + 24);
373 parent_1 = getbe32(data + 24);
373 parent_2 = getbe32(data + 28);
374 parent_2 = getbe32(data + 28);
374 c_node_id = data + 32;
375 c_node_id = data + 32;
375
376
376 entry = Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
377 entry = Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
377 base_rev, link_rev, parent_1, parent_2, c_node_id,
378 base_rev, link_rev, parent_1, parent_2, c_node_id,
378 (Py_ssize_t)20);
379 (Py_ssize_t)20);
379
380
380 if (entry) {
381 if (entry) {
381 PyObject_GC_UnTrack(entry);
382 PyObject_GC_UnTrack(entry);
382 Py_INCREF(entry);
383 Py_INCREF(entry);
383 }
384 }
384
385
385 self->cache[pos] = entry;
386 self->cache[pos] = entry;
386
387
387 return entry;
388 return entry;
388 }
389 }
389
390
390 /*
391 /*
391 * Return the 20-byte SHA of the node corresponding to the given rev.
392 * Return the 20-byte SHA of the node corresponding to the given rev.
392 */
393 */
393 static const char *index_node(indexObject *self, Py_ssize_t pos)
394 static const char *index_node(indexObject *self, Py_ssize_t pos)
394 {
395 {
395 Py_ssize_t length = index_length(self);
396 Py_ssize_t length = index_length(self);
396 const char *data;
397 const char *data;
397
398
398 if (pos == nullrev)
399 if (pos == nullrev)
399 return nullid;
400 return nullid;
400
401
401 if (pos >= length)
402 if (pos >= length)
402 return NULL;
403 return NULL;
403
404
404 if (pos >= self->length) {
405 if (pos >= self->length) {
405 PyObject *tuple, *str;
406 PyObject *tuple, *str;
406 tuple = PyList_GET_ITEM(self->added, pos - self->length);
407 tuple = PyList_GET_ITEM(self->added, pos - self->length);
407 str = PyTuple_GetItem(tuple, 7);
408 str = PyTuple_GetItem(tuple, 7);
408 return str ? PyBytes_AS_STRING(str) : NULL;
409 return str ? PyBytes_AS_STRING(str) : NULL;
409 }
410 }
410
411
411 data = index_deref(self, pos);
412 data = index_deref(self, pos);
412 return data ? data + 32 : NULL;
413 return data ? data + 32 : NULL;
413 }
414 }
414
415
415 /*
416 /*
416 * Return the 20-byte SHA of the node corresponding to the given rev. The
417 * Return the 20-byte SHA of the node corresponding to the given rev. The
417 * rev is assumed to be existing. If not, an exception is set.
418 * rev is assumed to be existing. If not, an exception is set.
418 */
419 */
419 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
420 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
420 {
421 {
421 const char *node = index_node(self, pos);
422 const char *node = index_node(self, pos);
422 if (node == NULL) {
423 if (node == NULL) {
423 PyErr_Format(PyExc_IndexError, "could not access rev %d",
424 PyErr_Format(PyExc_IndexError, "could not access rev %d",
424 (int)pos);
425 (int)pos);
425 }
426 }
426 return node;
427 return node;
427 }
428 }
428
429
429 static int nt_insert(nodetree *self, const char *node, int rev);
430 static int nt_insert(nodetree *self, const char *node, int rev);
430
431
431 static int node_check(PyObject *obj, char **node)
432 static int node_check(PyObject *obj, char **node)
432 {
433 {
433 Py_ssize_t nodelen;
434 Py_ssize_t nodelen;
434 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
435 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
435 return -1;
436 return -1;
436 if (nodelen == 20)
437 if (nodelen == 20)
437 return 0;
438 return 0;
438 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
439 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
439 return -1;
440 return -1;
440 }
441 }
441
442
442 static PyObject *index_append(indexObject *self, PyObject *obj)
443 static PyObject *index_append(indexObject *self, PyObject *obj)
443 {
444 {
444 char *node;
445 char *node;
445 Py_ssize_t len;
446 Py_ssize_t len;
446
447
447 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
448 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
448 PyErr_SetString(PyExc_TypeError, "8-tuple required");
449 PyErr_SetString(PyExc_TypeError, "8-tuple required");
449 return NULL;
450 return NULL;
450 }
451 }
451
452
452 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
453 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
453 return NULL;
454 return NULL;
454
455
455 len = index_length(self);
456 len = index_length(self);
456
457
457 if (self->added == NULL) {
458 if (self->added == NULL) {
458 self->added = PyList_New(0);
459 self->added = PyList_New(0);
459 if (self->added == NULL)
460 if (self->added == NULL)
460 return NULL;
461 return NULL;
461 }
462 }
462
463
463 if (PyList_Append(self->added, obj) == -1)
464 if (PyList_Append(self->added, obj) == -1)
464 return NULL;
465 return NULL;
465
466
466 if (self->ntinitialized)
467 if (self->ntinitialized)
467 nt_insert(&self->nt, node, (int)len);
468 nt_insert(&self->nt, node, (int)len);
468
469
469 Py_CLEAR(self->headrevs);
470 Py_CLEAR(self->headrevs);
470 Py_RETURN_NONE;
471 Py_RETURN_NONE;
471 }
472 }
472
473
473 static PyObject *index_stats(indexObject *self)
474 static PyObject *index_stats(indexObject *self)
474 {
475 {
475 PyObject *obj = PyDict_New();
476 PyObject *obj = PyDict_New();
476 PyObject *s = NULL;
477 PyObject *s = NULL;
477 PyObject *t = NULL;
478 PyObject *t = NULL;
478
479
479 if (obj == NULL)
480 if (obj == NULL)
480 return NULL;
481 return NULL;
481
482
482 #define istat(__n, __d) \
483 #define istat(__n, __d) \
483 do { \
484 do { \
484 s = PyBytes_FromString(__d); \
485 s = PyBytes_FromString(__d); \
485 t = PyInt_FromSsize_t(self->__n); \
486 t = PyInt_FromSsize_t(self->__n); \
486 if (!s || !t) \
487 if (!s || !t) \
487 goto bail; \
488 goto bail; \
488 if (PyDict_SetItem(obj, s, t) == -1) \
489 if (PyDict_SetItem(obj, s, t) == -1) \
489 goto bail; \
490 goto bail; \
490 Py_CLEAR(s); \
491 Py_CLEAR(s); \
491 Py_CLEAR(t); \
492 Py_CLEAR(t); \
492 } while (0)
493 } while (0)
493
494
494 if (self->added) {
495 if (self->added) {
495 Py_ssize_t len = PyList_GET_SIZE(self->added);
496 Py_ssize_t len = PyList_GET_SIZE(self->added);
496 s = PyBytes_FromString("index entries added");
497 s = PyBytes_FromString("index entries added");
497 t = PyInt_FromSsize_t(len);
498 t = PyInt_FromSsize_t(len);
498 if (!s || !t)
499 if (!s || !t)
499 goto bail;
500 goto bail;
500 if (PyDict_SetItem(obj, s, t) == -1)
501 if (PyDict_SetItem(obj, s, t) == -1)
501 goto bail;
502 goto bail;
502 Py_CLEAR(s);
503 Py_CLEAR(s);
503 Py_CLEAR(t);
504 Py_CLEAR(t);
504 }
505 }
505
506
506 if (self->raw_length != self->length)
507 if (self->raw_length != self->length)
507 istat(raw_length, "revs on disk");
508 istat(raw_length, "revs on disk");
508 istat(length, "revs in memory");
509 istat(length, "revs in memory");
509 istat(ntlookups, "node trie lookups");
510 istat(ntlookups, "node trie lookups");
510 istat(ntmisses, "node trie misses");
511 istat(ntmisses, "node trie misses");
511 istat(ntrev, "node trie last rev scanned");
512 istat(ntrev, "node trie last rev scanned");
512 if (self->ntinitialized) {
513 if (self->ntinitialized) {
513 istat(nt.capacity, "node trie capacity");
514 istat(nt.capacity, "node trie capacity");
514 istat(nt.depth, "node trie depth");
515 istat(nt.depth, "node trie depth");
515 istat(nt.length, "node trie count");
516 istat(nt.length, "node trie count");
516 istat(nt.splits, "node trie splits");
517 istat(nt.splits, "node trie splits");
517 }
518 }
518
519
519 #undef istat
520 #undef istat
520
521
521 return obj;
522 return obj;
522
523
523 bail:
524 bail:
524 Py_XDECREF(obj);
525 Py_XDECREF(obj);
525 Py_XDECREF(s);
526 Py_XDECREF(s);
526 Py_XDECREF(t);
527 Py_XDECREF(t);
527 return NULL;
528 return NULL;
528 }
529 }
529
530
530 /*
531 /*
531 * When we cache a list, we want to be sure the caller can't mutate
532 * When we cache a list, we want to be sure the caller can't mutate
532 * the cached copy.
533 * the cached copy.
533 */
534 */
534 static PyObject *list_copy(PyObject *list)
535 static PyObject *list_copy(PyObject *list)
535 {
536 {
536 Py_ssize_t len = PyList_GET_SIZE(list);
537 Py_ssize_t len = PyList_GET_SIZE(list);
537 PyObject *newlist = PyList_New(len);
538 PyObject *newlist = PyList_New(len);
538 Py_ssize_t i;
539 Py_ssize_t i;
539
540
540 if (newlist == NULL)
541 if (newlist == NULL)
541 return NULL;
542 return NULL;
542
543
543 for (i = 0; i < len; i++) {
544 for (i = 0; i < len; i++) {
544 PyObject *obj = PyList_GET_ITEM(list, i);
545 PyObject *obj = PyList_GET_ITEM(list, i);
545 Py_INCREF(obj);
546 Py_INCREF(obj);
546 PyList_SET_ITEM(newlist, i, obj);
547 PyList_SET_ITEM(newlist, i, obj);
547 }
548 }
548
549
549 return newlist;
550 return newlist;
550 }
551 }
551
552
552 static int check_filter(PyObject *filter, Py_ssize_t arg)
553 static int check_filter(PyObject *filter, Py_ssize_t arg)
553 {
554 {
554 if (filter) {
555 if (filter) {
555 PyObject *arglist, *result;
556 PyObject *arglist, *result;
556 int isfiltered;
557 int isfiltered;
557
558
558 arglist = Py_BuildValue("(n)", arg);
559 arglist = Py_BuildValue("(n)", arg);
559 if (!arglist) {
560 if (!arglist) {
560 return -1;
561 return -1;
561 }
562 }
562
563
563 result = PyEval_CallObject(filter, arglist);
564 result = PyEval_CallObject(filter, arglist);
564 Py_DECREF(arglist);
565 Py_DECREF(arglist);
565 if (!result) {
566 if (!result) {
566 return -1;
567 return -1;
567 }
568 }
568
569
569 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
570 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
570 * same as this function, so we can just return it directly.*/
571 * same as this function, so we can just return it directly.*/
571 isfiltered = PyObject_IsTrue(result);
572 isfiltered = PyObject_IsTrue(result);
572 Py_DECREF(result);
573 Py_DECREF(result);
573 return isfiltered;
574 return isfiltered;
574 } else {
575 } else {
575 return 0;
576 return 0;
576 }
577 }
577 }
578 }
578
579
579 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
580 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
580 Py_ssize_t marker, char *phases)
581 Py_ssize_t marker, char *phases)
581 {
582 {
582 PyObject *iter = NULL;
583 PyObject *iter = NULL;
583 PyObject *iter_item = NULL;
584 PyObject *iter_item = NULL;
584 Py_ssize_t min_idx = index_length(self) + 2;
585 Py_ssize_t min_idx = index_length(self) + 2;
585 long iter_item_long;
586 long iter_item_long;
586
587
587 if (PyList_GET_SIZE(list) != 0) {
588 if (PyList_GET_SIZE(list) != 0) {
588 iter = PyObject_GetIter(list);
589 iter = PyObject_GetIter(list);
589 if (iter == NULL)
590 if (iter == NULL)
590 return -2;
591 return -2;
591 while ((iter_item = PyIter_Next(iter))) {
592 while ((iter_item = PyIter_Next(iter))) {
592 if (!pylong_to_long(iter_item, &iter_item_long)) {
593 if (!pylong_to_long(iter_item, &iter_item_long)) {
593 Py_DECREF(iter_item);
594 Py_DECREF(iter_item);
594 return -2;
595 return -2;
595 }
596 }
596 Py_DECREF(iter_item);
597 Py_DECREF(iter_item);
597 if (iter_item_long < min_idx)
598 if (iter_item_long < min_idx)
598 min_idx = iter_item_long;
599 min_idx = iter_item_long;
599 phases[iter_item_long] = (char)marker;
600 phases[iter_item_long] = (char)marker;
600 }
601 }
601 Py_DECREF(iter);
602 Py_DECREF(iter);
602 }
603 }
603
604
604 return min_idx;
605 return min_idx;
605 }
606 }
606
607
607 static inline void set_phase_from_parents(char *phases, int parent_1,
608 static inline void set_phase_from_parents(char *phases, int parent_1,
608 int parent_2, Py_ssize_t i)
609 int parent_2, Py_ssize_t i)
609 {
610 {
610 if (parent_1 >= 0 && phases[parent_1] > phases[i])
611 if (parent_1 >= 0 && phases[parent_1] > phases[i])
611 phases[i] = phases[parent_1];
612 phases[i] = phases[parent_1];
612 if (parent_2 >= 0 && phases[parent_2] > phases[i])
613 if (parent_2 >= 0 && phases[parent_2] > phases[i])
613 phases[i] = phases[parent_2];
614 phases[i] = phases[parent_2];
614 }
615 }
615
616
616 static PyObject *reachableroots2(indexObject *self, PyObject *args)
617 static PyObject *reachableroots2(indexObject *self, PyObject *args)
617 {
618 {
618
619
619 /* Input */
620 /* Input */
620 long minroot;
621 long minroot;
621 PyObject *includepatharg = NULL;
622 PyObject *includepatharg = NULL;
622 int includepath = 0;
623 int includepath = 0;
623 /* heads and roots are lists */
624 /* heads and roots are lists */
624 PyObject *heads = NULL;
625 PyObject *heads = NULL;
625 PyObject *roots = NULL;
626 PyObject *roots = NULL;
626 PyObject *reachable = NULL;
627 PyObject *reachable = NULL;
627
628
628 PyObject *val;
629 PyObject *val;
629 Py_ssize_t len = index_length(self);
630 Py_ssize_t len = index_length(self);
630 long revnum;
631 long revnum;
631 Py_ssize_t k;
632 Py_ssize_t k;
632 Py_ssize_t i;
633 Py_ssize_t i;
633 Py_ssize_t l;
634 Py_ssize_t l;
634 int r;
635 int r;
635 int parents[2];
636 int parents[2];
636
637
637 /* Internal data structure:
638 /* Internal data structure:
638 * tovisit: array of length len+1 (all revs + nullrev), filled upto
639 * tovisit: array of length len+1 (all revs + nullrev), filled upto
639 * lentovisit
640 * lentovisit
640 *
641 *
641 * revstates: array of length len+1 (all revs + nullrev) */
642 * revstates: array of length len+1 (all revs + nullrev) */
642 int *tovisit = NULL;
643 int *tovisit = NULL;
643 long lentovisit = 0;
644 long lentovisit = 0;
644 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
645 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
645 char *revstates = NULL;
646 char *revstates = NULL;
646
647
647 /* Get arguments */
648 /* Get arguments */
648 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
649 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
649 &PyList_Type, &roots, &PyBool_Type,
650 &PyList_Type, &roots, &PyBool_Type,
650 &includepatharg))
651 &includepatharg))
651 goto bail;
652 goto bail;
652
653
653 if (includepatharg == Py_True)
654 if (includepatharg == Py_True)
654 includepath = 1;
655 includepath = 1;
655
656
656 /* Initialize return set */
657 /* Initialize return set */
657 reachable = PyList_New(0);
658 reachable = PyList_New(0);
658 if (reachable == NULL)
659 if (reachable == NULL)
659 goto bail;
660 goto bail;
660
661
661 /* Initialize internal datastructures */
662 /* Initialize internal datastructures */
662 tovisit = (int *)malloc((len + 1) * sizeof(int));
663 tovisit = (int *)malloc((len + 1) * sizeof(int));
663 if (tovisit == NULL) {
664 if (tovisit == NULL) {
664 PyErr_NoMemory();
665 PyErr_NoMemory();
665 goto bail;
666 goto bail;
666 }
667 }
667
668
668 revstates = (char *)calloc(len + 1, 1);
669 revstates = (char *)calloc(len + 1, 1);
669 if (revstates == NULL) {
670 if (revstates == NULL) {
670 PyErr_NoMemory();
671 PyErr_NoMemory();
671 goto bail;
672 goto bail;
672 }
673 }
673
674
674 l = PyList_GET_SIZE(roots);
675 l = PyList_GET_SIZE(roots);
675 for (i = 0; i < l; i++) {
676 for (i = 0; i < l; i++) {
676 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
677 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
677 if (revnum == -1 && PyErr_Occurred())
678 if (revnum == -1 && PyErr_Occurred())
678 goto bail;
679 goto bail;
679 /* If root is out of range, e.g. wdir(), it must be unreachable
680 /* If root is out of range, e.g. wdir(), it must be unreachable
680 * from heads. So we can just ignore it. */
681 * from heads. So we can just ignore it. */
681 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
682 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
682 continue;
683 continue;
683 revstates[revnum + 1] |= RS_ROOT;
684 revstates[revnum + 1] |= RS_ROOT;
684 }
685 }
685
686
686 /* Populate tovisit with all the heads */
687 /* Populate tovisit with all the heads */
687 l = PyList_GET_SIZE(heads);
688 l = PyList_GET_SIZE(heads);
688 for (i = 0; i < l; i++) {
689 for (i = 0; i < l; i++) {
689 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
690 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
690 if (revnum == -1 && PyErr_Occurred())
691 if (revnum == -1 && PyErr_Occurred())
691 goto bail;
692 goto bail;
692 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
693 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
693 PyErr_SetString(PyExc_IndexError, "head out of range");
694 PyErr_SetString(PyExc_IndexError, "head out of range");
694 goto bail;
695 goto bail;
695 }
696 }
696 if (!(revstates[revnum + 1] & RS_SEEN)) {
697 if (!(revstates[revnum + 1] & RS_SEEN)) {
697 tovisit[lentovisit++] = (int)revnum;
698 tovisit[lentovisit++] = (int)revnum;
698 revstates[revnum + 1] |= RS_SEEN;
699 revstates[revnum + 1] |= RS_SEEN;
699 }
700 }
700 }
701 }
701
702
702 /* Visit the tovisit list and find the reachable roots */
703 /* Visit the tovisit list and find the reachable roots */
703 k = 0;
704 k = 0;
704 while (k < lentovisit) {
705 while (k < lentovisit) {
705 /* Add the node to reachable if it is a root*/
706 /* Add the node to reachable if it is a root*/
706 revnum = tovisit[k++];
707 revnum = tovisit[k++];
707 if (revstates[revnum + 1] & RS_ROOT) {
708 if (revstates[revnum + 1] & RS_ROOT) {
708 revstates[revnum + 1] |= RS_REACHABLE;
709 revstates[revnum + 1] |= RS_REACHABLE;
709 val = PyInt_FromLong(revnum);
710 val = PyInt_FromLong(revnum);
710 if (val == NULL)
711 if (val == NULL)
711 goto bail;
712 goto bail;
712 r = PyList_Append(reachable, val);
713 r = PyList_Append(reachable, val);
713 Py_DECREF(val);
714 Py_DECREF(val);
714 if (r < 0)
715 if (r < 0)
715 goto bail;
716 goto bail;
716 if (includepath == 0)
717 if (includepath == 0)
717 continue;
718 continue;
718 }
719 }
719
720
720 /* Add its parents to the list of nodes to visit */
721 /* Add its parents to the list of nodes to visit */
721 if (revnum == nullrev)
722 if (revnum == nullrev)
722 continue;
723 continue;
723 r = index_get_parents(self, revnum, parents, (int)len - 1);
724 r = index_get_parents(self, revnum, parents, (int)len - 1);
724 if (r < 0)
725 if (r < 0)
725 goto bail;
726 goto bail;
726 for (i = 0; i < 2; i++) {
727 for (i = 0; i < 2; i++) {
727 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
728 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
728 parents[i] >= minroot) {
729 parents[i] >= minroot) {
729 tovisit[lentovisit++] = parents[i];
730 tovisit[lentovisit++] = parents[i];
730 revstates[parents[i] + 1] |= RS_SEEN;
731 revstates[parents[i] + 1] |= RS_SEEN;
731 }
732 }
732 }
733 }
733 }
734 }
734
735
735 /* Find all the nodes in between the roots we found and the heads
736 /* Find all the nodes in between the roots we found and the heads
736 * and add them to the reachable set */
737 * and add them to the reachable set */
737 if (includepath == 1) {
738 if (includepath == 1) {
738 long minidx = minroot;
739 long minidx = minroot;
739 if (minidx < 0)
740 if (minidx < 0)
740 minidx = 0;
741 minidx = 0;
741 for (i = minidx; i < len; i++) {
742 for (i = minidx; i < len; i++) {
742 if (!(revstates[i + 1] & RS_SEEN))
743 if (!(revstates[i + 1] & RS_SEEN))
743 continue;
744 continue;
744 r = index_get_parents(self, i, parents, (int)len - 1);
745 r = index_get_parents(self, i, parents, (int)len - 1);
745 /* Corrupted index file, error is set from
746 /* Corrupted index file, error is set from
746 * index_get_parents */
747 * index_get_parents */
747 if (r < 0)
748 if (r < 0)
748 goto bail;
749 goto bail;
749 if (((revstates[parents[0] + 1] |
750 if (((revstates[parents[0] + 1] |
750 revstates[parents[1] + 1]) &
751 revstates[parents[1] + 1]) &
751 RS_REACHABLE) &&
752 RS_REACHABLE) &&
752 !(revstates[i + 1] & RS_REACHABLE)) {
753 !(revstates[i + 1] & RS_REACHABLE)) {
753 revstates[i + 1] |= RS_REACHABLE;
754 revstates[i + 1] |= RS_REACHABLE;
754 val = PyInt_FromSsize_t(i);
755 val = PyInt_FromSsize_t(i);
755 if (val == NULL)
756 if (val == NULL)
756 goto bail;
757 goto bail;
757 r = PyList_Append(reachable, val);
758 r = PyList_Append(reachable, val);
758 Py_DECREF(val);
759 Py_DECREF(val);
759 if (r < 0)
760 if (r < 0)
760 goto bail;
761 goto bail;
761 }
762 }
762 }
763 }
763 }
764 }
764
765
765 free(revstates);
766 free(revstates);
766 free(tovisit);
767 free(tovisit);
767 return reachable;
768 return reachable;
768 bail:
769 bail:
769 Py_XDECREF(reachable);
770 Py_XDECREF(reachable);
770 free(revstates);
771 free(revstates);
771 free(tovisit);
772 free(tovisit);
772 return NULL;
773 return NULL;
773 }
774 }
774
775
775 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
776 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
776 {
777 {
777 PyObject *roots = Py_None;
778 PyObject *roots = Py_None;
778 PyObject *ret = NULL;
779 PyObject *ret = NULL;
779 PyObject *phasessize = NULL;
780 PyObject *phasessize = NULL;
780 PyObject *phaseroots = NULL;
781 PyObject *phaseroots = NULL;
781 PyObject *phaseset = NULL;
782 PyObject *phaseset = NULL;
782 PyObject *phasessetlist = NULL;
783 PyObject *phasessetlist = NULL;
783 PyObject *rev = NULL;
784 PyObject *rev = NULL;
784 Py_ssize_t len = index_length(self);
785 Py_ssize_t len = index_length(self);
785 Py_ssize_t numphase = 0;
786 Py_ssize_t numphase = 0;
786 Py_ssize_t minrevallphases = 0;
787 Py_ssize_t minrevallphases = 0;
787 Py_ssize_t minrevphase = 0;
788 Py_ssize_t minrevphase = 0;
788 Py_ssize_t i = 0;
789 Py_ssize_t i = 0;
789 char *phases = NULL;
790 char *phases = NULL;
790 long phase;
791 long phase;
791
792
792 if (!PyArg_ParseTuple(args, "O", &roots))
793 if (!PyArg_ParseTuple(args, "O", &roots))
793 goto done;
794 goto done;
794 if (roots == NULL || !PyList_Check(roots)) {
795 if (roots == NULL || !PyList_Check(roots)) {
795 PyErr_SetString(PyExc_TypeError, "roots must be a list");
796 PyErr_SetString(PyExc_TypeError, "roots must be a list");
796 goto done;
797 goto done;
797 }
798 }
798
799
799 phases = calloc(
800 phases = calloc(
800 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
801 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
801 if (phases == NULL) {
802 if (phases == NULL) {
802 PyErr_NoMemory();
803 PyErr_NoMemory();
803 goto done;
804 goto done;
804 }
805 }
805 /* Put the phase information of all the roots in phases */
806 /* Put the phase information of all the roots in phases */
806 numphase = PyList_GET_SIZE(roots) + 1;
807 numphase = PyList_GET_SIZE(roots) + 1;
807 minrevallphases = len + 1;
808 minrevallphases = len + 1;
808 phasessetlist = PyList_New(numphase);
809 phasessetlist = PyList_New(numphase);
809 if (phasessetlist == NULL)
810 if (phasessetlist == NULL)
810 goto done;
811 goto done;
811
812
812 PyList_SET_ITEM(phasessetlist, 0, Py_None);
813 PyList_SET_ITEM(phasessetlist, 0, Py_None);
813 Py_INCREF(Py_None);
814 Py_INCREF(Py_None);
814
815
815 for (i = 0; i < numphase - 1; i++) {
816 for (i = 0; i < numphase - 1; i++) {
816 phaseroots = PyList_GET_ITEM(roots, i);
817 phaseroots = PyList_GET_ITEM(roots, i);
817 phaseset = PySet_New(NULL);
818 phaseset = PySet_New(NULL);
818 if (phaseset == NULL)
819 if (phaseset == NULL)
819 goto release;
820 goto release;
820 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
821 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
821 if (!PyList_Check(phaseroots)) {
822 if (!PyList_Check(phaseroots)) {
822 PyErr_SetString(PyExc_TypeError,
823 PyErr_SetString(PyExc_TypeError,
823 "roots item must be a list");
824 "roots item must be a list");
824 goto release;
825 goto release;
825 }
826 }
826 minrevphase =
827 minrevphase =
827 add_roots_get_min(self, phaseroots, i + 1, phases);
828 add_roots_get_min(self, phaseroots, i + 1, phases);
828 if (minrevphase == -2) /* Error from add_roots_get_min */
829 if (minrevphase == -2) /* Error from add_roots_get_min */
829 goto release;
830 goto release;
830 minrevallphases = MIN(minrevallphases, minrevphase);
831 minrevallphases = MIN(minrevallphases, minrevphase);
831 }
832 }
832 /* Propagate the phase information from the roots to the revs */
833 /* Propagate the phase information from the roots to the revs */
833 if (minrevallphases != -1) {
834 if (minrevallphases != -1) {
834 int parents[2];
835 int parents[2];
835 for (i = minrevallphases; i < len; i++) {
836 for (i = minrevallphases; i < len; i++) {
836 if (index_get_parents(self, i, parents, (int)len - 1) <
837 if (index_get_parents(self, i, parents, (int)len - 1) <
837 0)
838 0)
838 goto release;
839 goto release;
839 set_phase_from_parents(phases, parents[0], parents[1],
840 set_phase_from_parents(phases, parents[0], parents[1],
840 i);
841 i);
841 }
842 }
842 }
843 }
843 /* Transform phase list to a python list */
844 /* Transform phase list to a python list */
844 phasessize = PyInt_FromSsize_t(len);
845 phasessize = PyInt_FromSsize_t(len);
845 if (phasessize == NULL)
846 if (phasessize == NULL)
846 goto release;
847 goto release;
847 for (i = 0; i < len; i++) {
848 for (i = 0; i < len; i++) {
848 phase = phases[i];
849 phase = phases[i];
849 /* We only store the sets of phase for non public phase, the
850 /* We only store the sets of phase for non public phase, the
850 * public phase is computed as a difference */
851 * public phase is computed as a difference */
851 if (phase != 0) {
852 if (phase != 0) {
852 phaseset = PyList_GET_ITEM(phasessetlist, phase);
853 phaseset = PyList_GET_ITEM(phasessetlist, phase);
853 rev = PyInt_FromSsize_t(i);
854 rev = PyInt_FromSsize_t(i);
854 if (rev == NULL)
855 if (rev == NULL)
855 goto release;
856 goto release;
856 PySet_Add(phaseset, rev);
857 PySet_Add(phaseset, rev);
857 Py_XDECREF(rev);
858 Py_XDECREF(rev);
858 }
859 }
859 }
860 }
860 ret = PyTuple_Pack(2, phasessize, phasessetlist);
861 ret = PyTuple_Pack(2, phasessize, phasessetlist);
861
862
862 release:
863 release:
863 Py_XDECREF(phasessize);
864 Py_XDECREF(phasessize);
864 Py_XDECREF(phasessetlist);
865 Py_XDECREF(phasessetlist);
865 done:
866 done:
866 free(phases);
867 free(phases);
867 return ret;
868 return ret;
868 }
869 }
869
870
870 static PyObject *index_headrevs(indexObject *self, PyObject *args)
871 static PyObject *index_headrevs(indexObject *self, PyObject *args)
871 {
872 {
872 Py_ssize_t i, j, len;
873 Py_ssize_t i, j, len;
873 char *nothead = NULL;
874 char *nothead = NULL;
874 PyObject *heads = NULL;
875 PyObject *heads = NULL;
875 PyObject *filter = NULL;
876 PyObject *filter = NULL;
876 PyObject *filteredrevs = Py_None;
877 PyObject *filteredrevs = Py_None;
877
878
878 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
879 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
879 return NULL;
880 return NULL;
880 }
881 }
881
882
882 if (self->headrevs && filteredrevs == self->filteredrevs)
883 if (self->headrevs && filteredrevs == self->filteredrevs)
883 return list_copy(self->headrevs);
884 return list_copy(self->headrevs);
884
885
885 Py_DECREF(self->filteredrevs);
886 Py_DECREF(self->filteredrevs);
886 self->filteredrevs = filteredrevs;
887 self->filteredrevs = filteredrevs;
887 Py_INCREF(filteredrevs);
888 Py_INCREF(filteredrevs);
888
889
889 if (filteredrevs != Py_None) {
890 if (filteredrevs != Py_None) {
890 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
891 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
891 if (!filter) {
892 if (!filter) {
892 PyErr_SetString(
893 PyErr_SetString(
893 PyExc_TypeError,
894 PyExc_TypeError,
894 "filteredrevs has no attribute __contains__");
895 "filteredrevs has no attribute __contains__");
895 goto bail;
896 goto bail;
896 }
897 }
897 }
898 }
898
899
899 len = index_length(self);
900 len = index_length(self);
900 heads = PyList_New(0);
901 heads = PyList_New(0);
901 if (heads == NULL)
902 if (heads == NULL)
902 goto bail;
903 goto bail;
903 if (len == 0) {
904 if (len == 0) {
904 PyObject *nullid = PyInt_FromLong(-1);
905 PyObject *nullid = PyInt_FromLong(-1);
905 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
906 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
906 Py_XDECREF(nullid);
907 Py_XDECREF(nullid);
907 goto bail;
908 goto bail;
908 }
909 }
909 goto done;
910 goto done;
910 }
911 }
911
912
912 nothead = calloc(len, 1);
913 nothead = calloc(len, 1);
913 if (nothead == NULL) {
914 if (nothead == NULL) {
914 PyErr_NoMemory();
915 PyErr_NoMemory();
915 goto bail;
916 goto bail;
916 }
917 }
917
918
918 for (i = len - 1; i >= 0; i--) {
919 for (i = len - 1; i >= 0; i--) {
919 int isfiltered;
920 int isfiltered;
920 int parents[2];
921 int parents[2];
921
922
922 /* If nothead[i] == 1, it means we've seen an unfiltered child
923 /* If nothead[i] == 1, it means we've seen an unfiltered child
923 * of this node already, and therefore this node is not
924 * of this node already, and therefore this node is not
924 * filtered. So we can skip the expensive check_filter step.
925 * filtered. So we can skip the expensive check_filter step.
925 */
926 */
926 if (nothead[i] != 1) {
927 if (nothead[i] != 1) {
927 isfiltered = check_filter(filter, i);
928 isfiltered = check_filter(filter, i);
928 if (isfiltered == -1) {
929 if (isfiltered == -1) {
929 PyErr_SetString(PyExc_TypeError,
930 PyErr_SetString(PyExc_TypeError,
930 "unable to check filter");
931 "unable to check filter");
931 goto bail;
932 goto bail;
932 }
933 }
933
934
934 if (isfiltered) {
935 if (isfiltered) {
935 nothead[i] = 1;
936 nothead[i] = 1;
936 continue;
937 continue;
937 }
938 }
938 }
939 }
939
940
940 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
941 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
941 goto bail;
942 goto bail;
942 for (j = 0; j < 2; j++) {
943 for (j = 0; j < 2; j++) {
943 if (parents[j] >= 0)
944 if (parents[j] >= 0)
944 nothead[parents[j]] = 1;
945 nothead[parents[j]] = 1;
945 }
946 }
946 }
947 }
947
948
948 for (i = 0; i < len; i++) {
949 for (i = 0; i < len; i++) {
949 PyObject *head;
950 PyObject *head;
950
951
951 if (nothead[i])
952 if (nothead[i])
952 continue;
953 continue;
953 head = PyInt_FromSsize_t(i);
954 head = PyInt_FromSsize_t(i);
954 if (head == NULL || PyList_Append(heads, head) == -1) {
955 if (head == NULL || PyList_Append(heads, head) == -1) {
955 Py_XDECREF(head);
956 Py_XDECREF(head);
956 goto bail;
957 goto bail;
957 }
958 }
958 }
959 }
959
960
960 done:
961 done:
961 self->headrevs = heads;
962 self->headrevs = heads;
962 Py_XDECREF(filter);
963 Py_XDECREF(filter);
963 free(nothead);
964 free(nothead);
964 return list_copy(self->headrevs);
965 return list_copy(self->headrevs);
965 bail:
966 bail:
966 Py_XDECREF(filter);
967 Py_XDECREF(filter);
967 Py_XDECREF(heads);
968 Py_XDECREF(heads);
968 free(nothead);
969 free(nothead);
969 return NULL;
970 return NULL;
970 }
971 }
971
972
972 /**
973 /**
973 * Obtain the base revision index entry.
974 * Obtain the base revision index entry.
974 *
975 *
975 * Callers must ensure that rev >= 0 or illegal memory access may occur.
976 * Callers must ensure that rev >= 0 or illegal memory access may occur.
976 */
977 */
977 static inline int index_baserev(indexObject *self, int rev)
978 static inline int index_baserev(indexObject *self, int rev)
978 {
979 {
979 const char *data;
980 const char *data;
980 int result;
981 int result;
981
982
982 if (rev >= self->length) {
983 if (rev >= self->length) {
983 PyObject *tuple =
984 PyObject *tuple =
984 PyList_GET_ITEM(self->added, rev - self->length);
985 PyList_GET_ITEM(self->added, rev - self->length);
985 long ret;
986 long ret;
986 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 3), &ret)) {
987 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 3), &ret)) {
987 return -2;
988 return -2;
988 }
989 }
989 result = (int)ret;
990 result = (int)ret;
990 } else {
991 } else {
991 data = index_deref(self, rev);
992 data = index_deref(self, rev);
992 if (data == NULL) {
993 if (data == NULL) {
993 return -2;
994 return -2;
994 }
995 }
995
996
996 result = getbe32(data + 16);
997 result = getbe32(data + 16);
997 }
998 }
998 if (result > rev) {
999 if (result > rev) {
999 PyErr_Format(
1000 PyErr_Format(
1000 PyExc_ValueError,
1001 PyExc_ValueError,
1001 "corrupted revlog, revision base above revision: %d, %d",
1002 "corrupted revlog, revision base above revision: %d, %d",
1002 rev, result);
1003 rev, result);
1003 return -2;
1004 return -2;
1004 }
1005 }
1005 if (result < -1) {
1006 if (result < -1) {
1006 PyErr_Format(
1007 PyErr_Format(
1007 PyExc_ValueError,
1008 PyExc_ValueError,
1008 "corrupted revlog, revision base out of range: %d, %d", rev,
1009 "corrupted revlog, revision base out of range: %d, %d", rev,
1009 result);
1010 result);
1010 return -2;
1011 return -2;
1011 }
1012 }
1012 return result;
1013 return result;
1013 }
1014 }
1014
1015
1015 /**
1016 /**
1016 * Find if a revision is a snapshot or not
1017 * Find if a revision is a snapshot or not
1017 *
1018 *
1018 * Only relevant for sparse-revlog case.
1019 * Only relevant for sparse-revlog case.
1019 * Callers must ensure that rev is in a valid range.
1020 * Callers must ensure that rev is in a valid range.
1020 */
1021 */
1021 static int index_issnapshotrev(indexObject *self, Py_ssize_t rev)
1022 static int index_issnapshotrev(indexObject *self, Py_ssize_t rev)
1022 {
1023 {
1023 int ps[2];
1024 int ps[2];
1024 Py_ssize_t base;
1025 Py_ssize_t base;
1025 while (rev >= 0) {
1026 while (rev >= 0) {
1026 base = (Py_ssize_t)index_baserev(self, rev);
1027 base = (Py_ssize_t)index_baserev(self, rev);
1027 if (base == rev) {
1028 if (base == rev) {
1028 base = -1;
1029 base = -1;
1029 }
1030 }
1030 if (base == -2) {
1031 if (base == -2) {
1031 assert(PyErr_Occurred());
1032 assert(PyErr_Occurred());
1032 return -1;
1033 return -1;
1033 }
1034 }
1034 if (base == -1) {
1035 if (base == -1) {
1035 return 1;
1036 return 1;
1036 }
1037 }
1037 if (index_get_parents(self, rev, ps, (int)rev) < 0) {
1038 if (index_get_parents(self, rev, ps, (int)rev) < 0) {
1038 assert(PyErr_Occurred());
1039 assert(PyErr_Occurred());
1039 return -1;
1040 return -1;
1040 };
1041 };
1041 if (base == ps[0] || base == ps[1]) {
1042 if (base == ps[0] || base == ps[1]) {
1042 return 0;
1043 return 0;
1043 }
1044 }
1044 rev = base;
1045 rev = base;
1045 }
1046 }
1046 return rev == -1;
1047 return rev == -1;
1047 }
1048 }
1048
1049
1049 static PyObject *index_issnapshot(indexObject *self, PyObject *value)
1050 static PyObject *index_issnapshot(indexObject *self, PyObject *value)
1050 {
1051 {
1051 long rev;
1052 long rev;
1052 int issnap;
1053 int issnap;
1053 Py_ssize_t length = index_length(self);
1054 Py_ssize_t length = index_length(self);
1054
1055
1055 if (!pylong_to_long(value, &rev)) {
1056 if (!pylong_to_long(value, &rev)) {
1056 return NULL;
1057 return NULL;
1057 }
1058 }
1058 if (rev < -1 || rev >= length) {
1059 if (rev < -1 || rev >= length) {
1059 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
1060 PyErr_Format(PyExc_ValueError, "revlog index out of range: %ld",
1060 rev);
1061 rev);
1061 return NULL;
1062 return NULL;
1062 };
1063 };
1063 issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
1064 issnap = index_issnapshotrev(self, (Py_ssize_t)rev);
1064 if (issnap < 0) {
1065 if (issnap < 0) {
1065 return NULL;
1066 return NULL;
1066 };
1067 };
1067 return PyBool_FromLong((long)issnap);
1068 return PyBool_FromLong((long)issnap);
1068 }
1069 }
1069
1070
1070 static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
1071 static PyObject *index_findsnapshots(indexObject *self, PyObject *args)
1071 {
1072 {
1072 Py_ssize_t start_rev;
1073 Py_ssize_t start_rev;
1073 PyObject *cache;
1074 PyObject *cache;
1074 Py_ssize_t base;
1075 Py_ssize_t base;
1075 Py_ssize_t rev;
1076 Py_ssize_t rev;
1076 PyObject *key = NULL;
1077 PyObject *key = NULL;
1077 PyObject *value = NULL;
1078 PyObject *value = NULL;
1078 const Py_ssize_t length = index_length(self);
1079 const Py_ssize_t length = index_length(self);
1079 if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
1080 if (!PyArg_ParseTuple(args, "O!n", &PyDict_Type, &cache, &start_rev)) {
1080 return NULL;
1081 return NULL;
1081 }
1082 }
1082 for (rev = start_rev; rev < length; rev++) {
1083 for (rev = start_rev; rev < length; rev++) {
1083 int issnap;
1084 int issnap;
1084 PyObject *allvalues = NULL;
1085 PyObject *allvalues = NULL;
1085 issnap = index_issnapshotrev(self, rev);
1086 issnap = index_issnapshotrev(self, rev);
1086 if (issnap < 0) {
1087 if (issnap < 0) {
1087 goto bail;
1088 goto bail;
1088 }
1089 }
1089 if (issnap == 0) {
1090 if (issnap == 0) {
1090 continue;
1091 continue;
1091 }
1092 }
1092 base = (Py_ssize_t)index_baserev(self, rev);
1093 base = (Py_ssize_t)index_baserev(self, rev);
1093 if (base == rev) {
1094 if (base == rev) {
1094 base = -1;
1095 base = -1;
1095 }
1096 }
1096 if (base == -2) {
1097 if (base == -2) {
1097 assert(PyErr_Occurred());
1098 assert(PyErr_Occurred());
1098 goto bail;
1099 goto bail;
1099 }
1100 }
1100 key = PyInt_FromSsize_t(base);
1101 key = PyInt_FromSsize_t(base);
1101 allvalues = PyDict_GetItem(cache, key);
1102 allvalues = PyDict_GetItem(cache, key);
1102 if (allvalues == NULL && PyErr_Occurred()) {
1103 if (allvalues == NULL && PyErr_Occurred()) {
1103 goto bail;
1104 goto bail;
1104 }
1105 }
1105 if (allvalues == NULL) {
1106 if (allvalues == NULL) {
1106 int r;
1107 int r;
1107 allvalues = PyList_New(0);
1108 allvalues = PyList_New(0);
1108 if (!allvalues) {
1109 if (!allvalues) {
1109 goto bail;
1110 goto bail;
1110 }
1111 }
1111 r = PyDict_SetItem(cache, key, allvalues);
1112 r = PyDict_SetItem(cache, key, allvalues);
1112 Py_DECREF(allvalues);
1113 Py_DECREF(allvalues);
1113 if (r < 0) {
1114 if (r < 0) {
1114 goto bail;
1115 goto bail;
1115 }
1116 }
1116 }
1117 }
1117 value = PyInt_FromSsize_t(rev);
1118 value = PyInt_FromSsize_t(rev);
1118 if (PyList_Append(allvalues, value)) {
1119 if (PyList_Append(allvalues, value)) {
1119 goto bail;
1120 goto bail;
1120 }
1121 }
1121 Py_CLEAR(key);
1122 Py_CLEAR(key);
1122 Py_CLEAR(value);
1123 Py_CLEAR(value);
1123 }
1124 }
1124 Py_RETURN_NONE;
1125 Py_RETURN_NONE;
1125 bail:
1126 bail:
1126 Py_XDECREF(key);
1127 Py_XDECREF(key);
1127 Py_XDECREF(value);
1128 Py_XDECREF(value);
1128 return NULL;
1129 return NULL;
1129 }
1130 }
1130
1131
1131 static PyObject *index_deltachain(indexObject *self, PyObject *args)
1132 static PyObject *index_deltachain(indexObject *self, PyObject *args)
1132 {
1133 {
1133 int rev, generaldelta;
1134 int rev, generaldelta;
1134 PyObject *stoparg;
1135 PyObject *stoparg;
1135 int stoprev, iterrev, baserev = -1;
1136 int stoprev, iterrev, baserev = -1;
1136 int stopped;
1137 int stopped;
1137 PyObject *chain = NULL, *result = NULL;
1138 PyObject *chain = NULL, *result = NULL;
1138 const Py_ssize_t length = index_length(self);
1139 const Py_ssize_t length = index_length(self);
1139
1140
1140 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
1141 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
1141 return NULL;
1142 return NULL;
1142 }
1143 }
1143
1144
1144 if (PyInt_Check(stoparg)) {
1145 if (PyInt_Check(stoparg)) {
1145 stoprev = (int)PyInt_AsLong(stoparg);
1146 stoprev = (int)PyInt_AsLong(stoparg);
1146 if (stoprev == -1 && PyErr_Occurred()) {
1147 if (stoprev == -1 && PyErr_Occurred()) {
1147 return NULL;
1148 return NULL;
1148 }
1149 }
1149 } else if (stoparg == Py_None) {
1150 } else if (stoparg == Py_None) {
1150 stoprev = -2;
1151 stoprev = -2;
1151 } else {
1152 } else {
1152 PyErr_SetString(PyExc_ValueError,
1153 PyErr_SetString(PyExc_ValueError,
1153 "stoprev must be integer or None");
1154 "stoprev must be integer or None");
1154 return NULL;
1155 return NULL;
1155 }
1156 }
1156
1157
1157 if (rev < 0 || rev >= length) {
1158 if (rev < 0 || rev >= length) {
1158 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1159 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1159 return NULL;
1160 return NULL;
1160 }
1161 }
1161
1162
1162 chain = PyList_New(0);
1163 chain = PyList_New(0);
1163 if (chain == NULL) {
1164 if (chain == NULL) {
1164 return NULL;
1165 return NULL;
1165 }
1166 }
1166
1167
1167 baserev = index_baserev(self, rev);
1168 baserev = index_baserev(self, rev);
1168
1169
1169 /* This should never happen. */
1170 /* This should never happen. */
1170 if (baserev <= -2) {
1171 if (baserev <= -2) {
1171 /* Error should be set by index_deref() */
1172 /* Error should be set by index_deref() */
1172 assert(PyErr_Occurred());
1173 assert(PyErr_Occurred());
1173 goto bail;
1174 goto bail;
1174 }
1175 }
1175
1176
1176 iterrev = rev;
1177 iterrev = rev;
1177
1178
1178 while (iterrev != baserev && iterrev != stoprev) {
1179 while (iterrev != baserev && iterrev != stoprev) {
1179 PyObject *value = PyInt_FromLong(iterrev);
1180 PyObject *value = PyInt_FromLong(iterrev);
1180 if (value == NULL) {
1181 if (value == NULL) {
1181 goto bail;
1182 goto bail;
1182 }
1183 }
1183 if (PyList_Append(chain, value)) {
1184 if (PyList_Append(chain, value)) {
1184 Py_DECREF(value);
1185 Py_DECREF(value);
1185 goto bail;
1186 goto bail;
1186 }
1187 }
1187 Py_DECREF(value);
1188 Py_DECREF(value);
1188
1189
1189 if (generaldelta) {
1190 if (generaldelta) {
1190 iterrev = baserev;
1191 iterrev = baserev;
1191 } else {
1192 } else {
1192 iterrev--;
1193 iterrev--;
1193 }
1194 }
1194
1195
1195 if (iterrev < 0) {
1196 if (iterrev < 0) {
1196 break;
1197 break;
1197 }
1198 }
1198
1199
1199 if (iterrev >= length) {
1200 if (iterrev >= length) {
1200 PyErr_SetString(PyExc_IndexError,
1201 PyErr_SetString(PyExc_IndexError,
1201 "revision outside index");
1202 "revision outside index");
1202 return NULL;
1203 return NULL;
1203 }
1204 }
1204
1205
1205 baserev = index_baserev(self, iterrev);
1206 baserev = index_baserev(self, iterrev);
1206
1207
1207 /* This should never happen. */
1208 /* This should never happen. */
1208 if (baserev <= -2) {
1209 if (baserev <= -2) {
1209 /* Error should be set by index_deref() */
1210 /* Error should be set by index_deref() */
1210 assert(PyErr_Occurred());
1211 assert(PyErr_Occurred());
1211 goto bail;
1212 goto bail;
1212 }
1213 }
1213 }
1214 }
1214
1215
1215 if (iterrev == stoprev) {
1216 if (iterrev == stoprev) {
1216 stopped = 1;
1217 stopped = 1;
1217 } else {
1218 } else {
1218 PyObject *value = PyInt_FromLong(iterrev);
1219 PyObject *value = PyInt_FromLong(iterrev);
1219 if (value == NULL) {
1220 if (value == NULL) {
1220 goto bail;
1221 goto bail;
1221 }
1222 }
1222 if (PyList_Append(chain, value)) {
1223 if (PyList_Append(chain, value)) {
1223 Py_DECREF(value);
1224 Py_DECREF(value);
1224 goto bail;
1225 goto bail;
1225 }
1226 }
1226 Py_DECREF(value);
1227 Py_DECREF(value);
1227
1228
1228 stopped = 0;
1229 stopped = 0;
1229 }
1230 }
1230
1231
1231 if (PyList_Reverse(chain)) {
1232 if (PyList_Reverse(chain)) {
1232 goto bail;
1233 goto bail;
1233 }
1234 }
1234
1235
1235 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1236 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1236 Py_DECREF(chain);
1237 Py_DECREF(chain);
1237 return result;
1238 return result;
1238
1239
1239 bail:
1240 bail:
1240 Py_DECREF(chain);
1241 Py_DECREF(chain);
1241 return NULL;
1242 return NULL;
1242 }
1243 }
1243
1244
1244 static inline int64_t
1245 static inline int64_t
1245 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1246 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1246 {
1247 {
1247 int64_t start_offset;
1248 int64_t start_offset;
1248 int64_t end_offset;
1249 int64_t end_offset;
1249 int end_size;
1250 int end_size;
1250 start_offset = index_get_start(self, start_rev);
1251 start_offset = index_get_start(self, start_rev);
1251 if (start_offset < 0) {
1252 if (start_offset < 0) {
1252 return -1;
1253 return -1;
1253 }
1254 }
1254 end_offset = index_get_start(self, end_rev);
1255 end_offset = index_get_start(self, end_rev);
1255 if (end_offset < 0) {
1256 if (end_offset < 0) {
1256 return -1;
1257 return -1;
1257 }
1258 }
1258 end_size = index_get_length(self, end_rev);
1259 end_size = index_get_length(self, end_rev);
1259 if (end_size < 0) {
1260 if (end_size < 0) {
1260 return -1;
1261 return -1;
1261 }
1262 }
1262 if (end_offset < start_offset) {
1263 if (end_offset < start_offset) {
1263 PyErr_Format(PyExc_ValueError,
1264 PyErr_Format(PyExc_ValueError,
1264 "corrupted revlog index: inconsistent offset "
1265 "corrupted revlog index: inconsistent offset "
1265 "between revisions (%zd) and (%zd)",
1266 "between revisions (%zd) and (%zd)",
1266 start_rev, end_rev);
1267 start_rev, end_rev);
1267 return -1;
1268 return -1;
1268 }
1269 }
1269 return (end_offset - start_offset) + (int64_t)end_size;
1270 return (end_offset - start_offset) + (int64_t)end_size;
1270 }
1271 }
1271
1272
1272 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1273 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1273 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1274 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1274 Py_ssize_t startidx, Py_ssize_t endidx)
1275 Py_ssize_t startidx, Py_ssize_t endidx)
1275 {
1276 {
1276 int length;
1277 int length;
1277 while (endidx > 1 && endidx > startidx) {
1278 while (endidx > 1 && endidx > startidx) {
1278 length = index_get_length(self, revs[endidx - 1]);
1279 length = index_get_length(self, revs[endidx - 1]);
1279 if (length < 0) {
1280 if (length < 0) {
1280 return -1;
1281 return -1;
1281 }
1282 }
1282 if (length != 0) {
1283 if (length != 0) {
1283 break;
1284 break;
1284 }
1285 }
1285 endidx -= 1;
1286 endidx -= 1;
1286 }
1287 }
1287 return endidx;
1288 return endidx;
1288 }
1289 }
1289
1290
1290 struct Gap {
1291 struct Gap {
1291 int64_t size;
1292 int64_t size;
1292 Py_ssize_t idx;
1293 Py_ssize_t idx;
1293 };
1294 };
1294
1295
1295 static int gap_compare(const void *left, const void *right)
1296 static int gap_compare(const void *left, const void *right)
1296 {
1297 {
1297 const struct Gap *l_left = ((const struct Gap *)left);
1298 const struct Gap *l_left = ((const struct Gap *)left);
1298 const struct Gap *l_right = ((const struct Gap *)right);
1299 const struct Gap *l_right = ((const struct Gap *)right);
1299 if (l_left->size < l_right->size) {
1300 if (l_left->size < l_right->size) {
1300 return -1;
1301 return -1;
1301 } else if (l_left->size > l_right->size) {
1302 } else if (l_left->size > l_right->size) {
1302 return 1;
1303 return 1;
1303 }
1304 }
1304 return 0;
1305 return 0;
1305 }
1306 }
1306 static int Py_ssize_t_compare(const void *left, const void *right)
1307 static int Py_ssize_t_compare(const void *left, const void *right)
1307 {
1308 {
1308 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1309 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1309 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1310 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1310 if (l_left < l_right) {
1311 if (l_left < l_right) {
1311 return -1;
1312 return -1;
1312 } else if (l_left > l_right) {
1313 } else if (l_left > l_right) {
1313 return 1;
1314 return 1;
1314 }
1315 }
1315 return 0;
1316 return 0;
1316 }
1317 }
1317
1318
1318 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1319 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1319 {
1320 {
1320 /* method arguments */
1321 /* method arguments */
1321 PyObject *list_revs = NULL; /* revisions in the chain */
1322 PyObject *list_revs = NULL; /* revisions in the chain */
1322 double targetdensity = 0; /* min density to achieve */
1323 double targetdensity = 0; /* min density to achieve */
1323 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1324 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1324
1325
1325 /* other core variables */
1326 /* other core variables */
1326 Py_ssize_t idxlen = index_length(self);
1327 Py_ssize_t idxlen = index_length(self);
1327 Py_ssize_t i; /* used for various iteration */
1328 Py_ssize_t i; /* used for various iteration */
1328 PyObject *result = NULL; /* the final return of the function */
1329 PyObject *result = NULL; /* the final return of the function */
1329
1330
1330 /* generic information about the delta chain being slice */
1331 /* generic information about the delta chain being slice */
1331 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1332 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1332 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1333 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1333 int64_t chainpayload = 0; /* sum of all delta in the chain */
1334 int64_t chainpayload = 0; /* sum of all delta in the chain */
1334 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1335 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1335
1336
1336 /* variable used for slicing the delta chain */
1337 /* variable used for slicing the delta chain */
1337 int64_t readdata = 0; /* amount of data currently planned to be read */
1338 int64_t readdata = 0; /* amount of data currently planned to be read */
1338 double density = 0; /* ration of payload data compared to read ones */
1339 double density = 0; /* ration of payload data compared to read ones */
1339 int64_t previous_end;
1340 int64_t previous_end;
1340 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1341 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1341 Py_ssize_t num_gaps =
1342 Py_ssize_t num_gaps =
1342 0; /* total number of notable gap recorded so far */
1343 0; /* total number of notable gap recorded so far */
1343 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1344 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1344 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1345 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1345 PyObject *chunk = NULL; /* individual slice */
1346 PyObject *chunk = NULL; /* individual slice */
1346 PyObject *allchunks = NULL; /* all slices */
1347 PyObject *allchunks = NULL; /* all slices */
1347 Py_ssize_t previdx;
1348 Py_ssize_t previdx;
1348
1349
1349 /* parsing argument */
1350 /* parsing argument */
1350 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1351 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1351 &targetdensity, &mingapsize)) {
1352 &targetdensity, &mingapsize)) {
1352 goto bail;
1353 goto bail;
1353 }
1354 }
1354
1355
1355 /* If the delta chain contains a single element, we do not need slicing
1356 /* If the delta chain contains a single element, we do not need slicing
1356 */
1357 */
1357 num_revs = PyList_GET_SIZE(list_revs);
1358 num_revs = PyList_GET_SIZE(list_revs);
1358 if (num_revs <= 1) {
1359 if (num_revs <= 1) {
1359 result = PyTuple_Pack(1, list_revs);
1360 result = PyTuple_Pack(1, list_revs);
1360 goto done;
1361 goto done;
1361 }
1362 }
1362
1363
1363 /* Turn the python list into a native integer array (for efficiency) */
1364 /* Turn the python list into a native integer array (for efficiency) */
1364 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1365 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1365 if (revs == NULL) {
1366 if (revs == NULL) {
1366 PyErr_NoMemory();
1367 PyErr_NoMemory();
1367 goto bail;
1368 goto bail;
1368 }
1369 }
1369 for (i = 0; i < num_revs; i++) {
1370 for (i = 0; i < num_revs; i++) {
1370 Py_ssize_t revnum = PyInt_AsLong(PyList_GET_ITEM(list_revs, i));
1371 Py_ssize_t revnum = PyInt_AsLong(PyList_GET_ITEM(list_revs, i));
1371 if (revnum == -1 && PyErr_Occurred()) {
1372 if (revnum == -1 && PyErr_Occurred()) {
1372 goto bail;
1373 goto bail;
1373 }
1374 }
1374 if (revnum < nullrev || revnum >= idxlen) {
1375 if (revnum < nullrev || revnum >= idxlen) {
1375 PyErr_Format(PyExc_IndexError,
1376 PyErr_Format(PyExc_IndexError,
1376 "index out of range: %zd", revnum);
1377 "index out of range: %zd", revnum);
1377 goto bail;
1378 goto bail;
1378 }
1379 }
1379 revs[i] = revnum;
1380 revs[i] = revnum;
1380 }
1381 }
1381
1382
1382 /* Compute and check various property of the unsliced delta chain */
1383 /* Compute and check various property of the unsliced delta chain */
1383 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1384 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1384 if (deltachainspan < 0) {
1385 if (deltachainspan < 0) {
1385 goto bail;
1386 goto bail;
1386 }
1387 }
1387
1388
1388 if (deltachainspan <= mingapsize) {
1389 if (deltachainspan <= mingapsize) {
1389 result = PyTuple_Pack(1, list_revs);
1390 result = PyTuple_Pack(1, list_revs);
1390 goto done;
1391 goto done;
1391 }
1392 }
1392 chainpayload = 0;
1393 chainpayload = 0;
1393 for (i = 0; i < num_revs; i++) {
1394 for (i = 0; i < num_revs; i++) {
1394 int tmp = index_get_length(self, revs[i]);
1395 int tmp = index_get_length(self, revs[i]);
1395 if (tmp < 0) {
1396 if (tmp < 0) {
1396 goto bail;
1397 goto bail;
1397 }
1398 }
1398 chainpayload += tmp;
1399 chainpayload += tmp;
1399 }
1400 }
1400
1401
1401 readdata = deltachainspan;
1402 readdata = deltachainspan;
1402 density = 1.0;
1403 density = 1.0;
1403
1404
1404 if (0 < deltachainspan) {
1405 if (0 < deltachainspan) {
1405 density = (double)chainpayload / (double)deltachainspan;
1406 density = (double)chainpayload / (double)deltachainspan;
1406 }
1407 }
1407
1408
1408 if (density >= targetdensity) {
1409 if (density >= targetdensity) {
1409 result = PyTuple_Pack(1, list_revs);
1410 result = PyTuple_Pack(1, list_revs);
1410 goto done;
1411 goto done;
1411 }
1412 }
1412
1413
1413 /* if chain is too sparse, look for relevant gaps */
1414 /* if chain is too sparse, look for relevant gaps */
1414 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1415 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1415 if (gaps == NULL) {
1416 if (gaps == NULL) {
1416 PyErr_NoMemory();
1417 PyErr_NoMemory();
1417 goto bail;
1418 goto bail;
1418 }
1419 }
1419
1420
1420 previous_end = -1;
1421 previous_end = -1;
1421 for (i = 0; i < num_revs; i++) {
1422 for (i = 0; i < num_revs; i++) {
1422 int64_t revstart;
1423 int64_t revstart;
1423 int revsize;
1424 int revsize;
1424 revstart = index_get_start(self, revs[i]);
1425 revstart = index_get_start(self, revs[i]);
1425 if (revstart < 0) {
1426 if (revstart < 0) {
1426 goto bail;
1427 goto bail;
1427 };
1428 };
1428 revsize = index_get_length(self, revs[i]);
1429 revsize = index_get_length(self, revs[i]);
1429 if (revsize < 0) {
1430 if (revsize < 0) {
1430 goto bail;
1431 goto bail;
1431 };
1432 };
1432 if (revsize == 0) {
1433 if (revsize == 0) {
1433 continue;
1434 continue;
1434 }
1435 }
1435 if (previous_end >= 0) {
1436 if (previous_end >= 0) {
1436 int64_t gapsize = revstart - previous_end;
1437 int64_t gapsize = revstart - previous_end;
1437 if (gapsize > mingapsize) {
1438 if (gapsize > mingapsize) {
1438 gaps[num_gaps].size = gapsize;
1439 gaps[num_gaps].size = gapsize;
1439 gaps[num_gaps].idx = i;
1440 gaps[num_gaps].idx = i;
1440 num_gaps += 1;
1441 num_gaps += 1;
1441 }
1442 }
1442 }
1443 }
1443 previous_end = revstart + revsize;
1444 previous_end = revstart + revsize;
1444 }
1445 }
1445 if (num_gaps == 0) {
1446 if (num_gaps == 0) {
1446 result = PyTuple_Pack(1, list_revs);
1447 result = PyTuple_Pack(1, list_revs);
1447 goto done;
1448 goto done;
1448 }
1449 }
1449 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1450 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1450
1451
1451 /* Slice the largest gap first, they improve the density the most */
1452 /* Slice the largest gap first, they improve the density the most */
1452 selected_indices =
1453 selected_indices =
1453 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1454 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1454 if (selected_indices == NULL) {
1455 if (selected_indices == NULL) {
1455 PyErr_NoMemory();
1456 PyErr_NoMemory();
1456 goto bail;
1457 goto bail;
1457 }
1458 }
1458
1459
1459 for (i = num_gaps - 1; i >= 0; i--) {
1460 for (i = num_gaps - 1; i >= 0; i--) {
1460 selected_indices[num_selected] = gaps[i].idx;
1461 selected_indices[num_selected] = gaps[i].idx;
1461 readdata -= gaps[i].size;
1462 readdata -= gaps[i].size;
1462 num_selected += 1;
1463 num_selected += 1;
1463 if (readdata <= 0) {
1464 if (readdata <= 0) {
1464 density = 1.0;
1465 density = 1.0;
1465 } else {
1466 } else {
1466 density = (double)chainpayload / (double)readdata;
1467 density = (double)chainpayload / (double)readdata;
1467 }
1468 }
1468 if (density >= targetdensity) {
1469 if (density >= targetdensity) {
1469 break;
1470 break;
1470 }
1471 }
1471 }
1472 }
1472 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1473 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1473 &Py_ssize_t_compare);
1474 &Py_ssize_t_compare);
1474
1475
1475 /* create the resulting slice */
1476 /* create the resulting slice */
1476 allchunks = PyList_New(0);
1477 allchunks = PyList_New(0);
1477 if (allchunks == NULL) {
1478 if (allchunks == NULL) {
1478 goto bail;
1479 goto bail;
1479 }
1480 }
1480 previdx = 0;
1481 previdx = 0;
1481 selected_indices[num_selected] = num_revs;
1482 selected_indices[num_selected] = num_revs;
1482 for (i = 0; i <= num_selected; i++) {
1483 for (i = 0; i <= num_selected; i++) {
1483 Py_ssize_t idx = selected_indices[i];
1484 Py_ssize_t idx = selected_indices[i];
1484 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1485 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1485 if (endidx < 0) {
1486 if (endidx < 0) {
1486 goto bail;
1487 goto bail;
1487 }
1488 }
1488 if (previdx < endidx) {
1489 if (previdx < endidx) {
1489 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1490 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1490 if (chunk == NULL) {
1491 if (chunk == NULL) {
1491 goto bail;
1492 goto bail;
1492 }
1493 }
1493 if (PyList_Append(allchunks, chunk) == -1) {
1494 if (PyList_Append(allchunks, chunk) == -1) {
1494 goto bail;
1495 goto bail;
1495 }
1496 }
1496 Py_DECREF(chunk);
1497 Py_DECREF(chunk);
1497 chunk = NULL;
1498 chunk = NULL;
1498 }
1499 }
1499 previdx = idx;
1500 previdx = idx;
1500 }
1501 }
1501 result = allchunks;
1502 result = allchunks;
1502 goto done;
1503 goto done;
1503
1504
1504 bail:
1505 bail:
1505 Py_XDECREF(allchunks);
1506 Py_XDECREF(allchunks);
1506 Py_XDECREF(chunk);
1507 Py_XDECREF(chunk);
1507 done:
1508 done:
1508 free(revs);
1509 free(revs);
1509 free(gaps);
1510 free(gaps);
1510 free(selected_indices);
1511 free(selected_indices);
1511 return result;
1512 return result;
1512 }
1513 }
1513
1514
1514 static inline int nt_level(const char *node, Py_ssize_t level)
1515 static inline int nt_level(const char *node, Py_ssize_t level)
1515 {
1516 {
1516 int v = node[level >> 1];
1517 int v = node[level >> 1];
1517 if (!(level & 1))
1518 if (!(level & 1))
1518 v >>= 4;
1519 v >>= 4;
1519 return v & 0xf;
1520 return v & 0xf;
1520 }
1521 }
1521
1522
1522 /*
1523 /*
1523 * Return values:
1524 * Return values:
1524 *
1525 *
1525 * -4: match is ambiguous (multiple candidates)
1526 * -4: match is ambiguous (multiple candidates)
1526 * -2: not found
1527 * -2: not found
1527 * rest: valid rev
1528 * rest: valid rev
1528 */
1529 */
1529 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1530 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1530 int hex)
1531 int hex)
1531 {
1532 {
1532 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1533 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1533 int level, maxlevel, off;
1534 int level, maxlevel, off;
1534
1535
1535 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1536 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1536 return -1;
1537 return -1;
1537
1538
1538 if (hex)
1539 if (hex)
1539 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1540 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1540 else
1541 else
1541 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1542 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1542
1543
1543 for (level = off = 0; level < maxlevel; level++) {
1544 for (level = off = 0; level < maxlevel; level++) {
1544 int k = getnybble(node, level);
1545 int k = getnybble(node, level);
1545 nodetreenode *n = &self->nodes[off];
1546 nodetreenode *n = &self->nodes[off];
1546 int v = n->children[k];
1547 int v = n->children[k];
1547
1548
1548 if (v < 0) {
1549 if (v < 0) {
1549 const char *n;
1550 const char *n;
1550 Py_ssize_t i;
1551 Py_ssize_t i;
1551
1552
1552 v = -(v + 2);
1553 v = -(v + 2);
1553 n = index_node(self->index, v);
1554 n = index_node(self->index, v);
1554 if (n == NULL)
1555 if (n == NULL)
1555 return -2;
1556 return -2;
1556 for (i = level; i < maxlevel; i++)
1557 for (i = level; i < maxlevel; i++)
1557 if (getnybble(node, i) != nt_level(n, i))
1558 if (getnybble(node, i) != nt_level(n, i))
1558 return -2;
1559 return -2;
1559 return v;
1560 return v;
1560 }
1561 }
1561 if (v == 0)
1562 if (v == 0)
1562 return -2;
1563 return -2;
1563 off = v;
1564 off = v;
1564 }
1565 }
1565 /* multiple matches against an ambiguous prefix */
1566 /* multiple matches against an ambiguous prefix */
1566 return -4;
1567 return -4;
1567 }
1568 }
1568
1569
1569 static int nt_new(nodetree *self)
1570 static int nt_new(nodetree *self)
1570 {
1571 {
1571 if (self->length == self->capacity) {
1572 if (self->length == self->capacity) {
1572 unsigned newcapacity;
1573 unsigned newcapacity;
1573 nodetreenode *newnodes;
1574 nodetreenode *newnodes;
1574 newcapacity = self->capacity * 2;
1575 newcapacity = self->capacity * 2;
1575 if (newcapacity >= INT_MAX / sizeof(nodetreenode)) {
1576 if (newcapacity >= INT_MAX / sizeof(nodetreenode)) {
1576 PyErr_SetString(PyExc_MemoryError,
1577 PyErr_SetString(PyExc_MemoryError,
1577 "overflow in nt_new");
1578 "overflow in nt_new");
1578 return -1;
1579 return -1;
1579 }
1580 }
1580 newnodes =
1581 newnodes =
1581 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1582 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1582 if (newnodes == NULL) {
1583 if (newnodes == NULL) {
1583 PyErr_SetString(PyExc_MemoryError, "out of memory");
1584 PyErr_SetString(PyExc_MemoryError, "out of memory");
1584 return -1;
1585 return -1;
1585 }
1586 }
1586 self->capacity = newcapacity;
1587 self->capacity = newcapacity;
1587 self->nodes = newnodes;
1588 self->nodes = newnodes;
1588 memset(&self->nodes[self->length], 0,
1589 memset(&self->nodes[self->length], 0,
1589 sizeof(nodetreenode) * (self->capacity - self->length));
1590 sizeof(nodetreenode) * (self->capacity - self->length));
1590 }
1591 }
1591 return self->length++;
1592 return self->length++;
1592 }
1593 }
1593
1594
1594 static int nt_insert(nodetree *self, const char *node, int rev)
1595 static int nt_insert(nodetree *self, const char *node, int rev)
1595 {
1596 {
1596 int level = 0;
1597 int level = 0;
1597 int off = 0;
1598 int off = 0;
1598
1599
1599 while (level < 40) {
1600 while (level < 40) {
1600 int k = nt_level(node, level);
1601 int k = nt_level(node, level);
1601 nodetreenode *n;
1602 nodetreenode *n;
1602 int v;
1603 int v;
1603
1604
1604 n = &self->nodes[off];
1605 n = &self->nodes[off];
1605 v = n->children[k];
1606 v = n->children[k];
1606
1607
1607 if (v == 0) {
1608 if (v == 0) {
1608 n->children[k] = -rev - 2;
1609 n->children[k] = -rev - 2;
1609 return 0;
1610 return 0;
1610 }
1611 }
1611 if (v < 0) {
1612 if (v < 0) {
1612 const char *oldnode =
1613 const char *oldnode =
1613 index_node_existing(self->index, -(v + 2));
1614 index_node_existing(self->index, -(v + 2));
1614 int noff;
1615 int noff;
1615
1616
1616 if (oldnode == NULL)
1617 if (oldnode == NULL)
1617 return -1;
1618 return -1;
1618 if (!memcmp(oldnode, node, 20)) {
1619 if (!memcmp(oldnode, node, 20)) {
1619 n->children[k] = -rev - 2;
1620 n->children[k] = -rev - 2;
1620 return 0;
1621 return 0;
1621 }
1622 }
1622 noff = nt_new(self);
1623 noff = nt_new(self);
1623 if (noff == -1)
1624 if (noff == -1)
1624 return -1;
1625 return -1;
1625 /* self->nodes may have been changed by realloc */
1626 /* self->nodes may have been changed by realloc */
1626 self->nodes[off].children[k] = noff;
1627 self->nodes[off].children[k] = noff;
1627 off = noff;
1628 off = noff;
1628 n = &self->nodes[off];
1629 n = &self->nodes[off];
1629 n->children[nt_level(oldnode, ++level)] = v;
1630 n->children[nt_level(oldnode, ++level)] = v;
1630 if (level > self->depth)
1631 if (level > self->depth)
1631 self->depth = level;
1632 self->depth = level;
1632 self->splits += 1;
1633 self->splits += 1;
1633 } else {
1634 } else {
1634 level += 1;
1635 level += 1;
1635 off = v;
1636 off = v;
1636 }
1637 }
1637 }
1638 }
1638
1639
1639 return -1;
1640 return -1;
1640 }
1641 }
1641
1642
1642 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1643 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1643 {
1644 {
1644 Py_ssize_t rev;
1645 Py_ssize_t rev;
1645 const char *node;
1646 const char *node;
1646 Py_ssize_t length;
1647 Py_ssize_t length;
1647 if (!PyArg_ParseTuple(args, "n", &rev))
1648 if (!PyArg_ParseTuple(args, "n", &rev))
1648 return NULL;
1649 return NULL;
1649 length = index_length(self->nt.index);
1650 length = index_length(self->nt.index);
1650 if (rev < 0 || rev >= length) {
1651 if (rev < 0 || rev >= length) {
1651 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1652 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1652 return NULL;
1653 return NULL;
1653 }
1654 }
1654 node = index_node_existing(self->nt.index, rev);
1655 node = index_node_existing(self->nt.index, rev);
1655 if (nt_insert(&self->nt, node, (int)rev) == -1)
1656 if (nt_insert(&self->nt, node, (int)rev) == -1)
1656 return NULL;
1657 return NULL;
1657 Py_RETURN_NONE;
1658 Py_RETURN_NONE;
1658 }
1659 }
1659
1660
1660 static int nt_delete_node(nodetree *self, const char *node)
1661 static int nt_delete_node(nodetree *self, const char *node)
1661 {
1662 {
1662 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
1663 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
1663 */
1664 */
1664 return nt_insert(self, node, -2);
1665 return nt_insert(self, node, -2);
1665 }
1666 }
1666
1667
1667 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
1668 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
1668 {
1669 {
1669 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
1670 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
1670 self->nodes = NULL;
1671 self->nodes = NULL;
1671
1672
1672 self->index = index;
1673 self->index = index;
1673 /* The input capacity is in terms of revisions, while the field is in
1674 /* The input capacity is in terms of revisions, while the field is in
1674 * terms of nodetree nodes. */
1675 * terms of nodetree nodes. */
1675 self->capacity = (capacity < 4 ? 4 : capacity / 2);
1676 self->capacity = (capacity < 4 ? 4 : capacity / 2);
1676 self->depth = 0;
1677 self->depth = 0;
1677 self->splits = 0;
1678 self->splits = 0;
1678 if ((size_t)self->capacity > INT_MAX / sizeof(nodetreenode)) {
1679 if ((size_t)self->capacity > INT_MAX / sizeof(nodetreenode)) {
1679 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
1680 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
1680 return -1;
1681 return -1;
1681 }
1682 }
1682 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
1683 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
1683 if (self->nodes == NULL) {
1684 if (self->nodes == NULL) {
1684 PyErr_NoMemory();
1685 PyErr_NoMemory();
1685 return -1;
1686 return -1;
1686 }
1687 }
1687 self->length = 1;
1688 self->length = 1;
1688 return 0;
1689 return 0;
1689 }
1690 }
1690
1691
1691 static int ntobj_init(nodetreeObject *self, PyObject *args)
1692 static int ntobj_init(nodetreeObject *self, PyObject *args)
1692 {
1693 {
1693 PyObject *index;
1694 PyObject *index;
1694 unsigned capacity;
1695 unsigned capacity;
1695 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
1696 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
1696 &capacity))
1697 &capacity))
1697 return -1;
1698 return -1;
1698 Py_INCREF(index);
1699 Py_INCREF(index);
1699 return nt_init(&self->nt, (indexObject *)index, capacity);
1700 return nt_init(&self->nt, (indexObject *)index, capacity);
1700 }
1701 }
1701
1702
1702 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
1703 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
1703 {
1704 {
1704 return nt_find(self, node, nodelen, 1);
1705 return nt_find(self, node, nodelen, 1);
1705 }
1706 }
1706
1707
1707 /*
1708 /*
1708 * Find the length of the shortest unique prefix of node.
1709 * Find the length of the shortest unique prefix of node.
1709 *
1710 *
1710 * Return values:
1711 * Return values:
1711 *
1712 *
1712 * -3: error (exception set)
1713 * -3: error (exception set)
1713 * -2: not found (no exception set)
1714 * -2: not found (no exception set)
1714 * rest: length of shortest prefix
1715 * rest: length of shortest prefix
1715 */
1716 */
1716 static int nt_shortest(nodetree *self, const char *node)
1717 static int nt_shortest(nodetree *self, const char *node)
1717 {
1718 {
1718 int level, off;
1719 int level, off;
1719
1720
1720 for (level = off = 0; level < 40; level++) {
1721 for (level = off = 0; level < 40; level++) {
1721 int k, v;
1722 int k, v;
1722 nodetreenode *n = &self->nodes[off];
1723 nodetreenode *n = &self->nodes[off];
1723 k = nt_level(node, level);
1724 k = nt_level(node, level);
1724 v = n->children[k];
1725 v = n->children[k];
1725 if (v < 0) {
1726 if (v < 0) {
1726 const char *n;
1727 const char *n;
1727 v = -(v + 2);
1728 v = -(v + 2);
1728 n = index_node_existing(self->index, v);
1729 n = index_node_existing(self->index, v);
1729 if (n == NULL)
1730 if (n == NULL)
1730 return -3;
1731 return -3;
1731 if (memcmp(node, n, 20) != 0)
1732 if (memcmp(node, n, 20) != 0)
1732 /*
1733 /*
1733 * Found a unique prefix, but it wasn't for the
1734 * Found a unique prefix, but it wasn't for the
1734 * requested node (i.e the requested node does
1735 * requested node (i.e the requested node does
1735 * not exist).
1736 * not exist).
1736 */
1737 */
1737 return -2;
1738 return -2;
1738 return level + 1;
1739 return level + 1;
1739 }
1740 }
1740 if (v == 0)
1741 if (v == 0)
1741 return -2;
1742 return -2;
1742 off = v;
1743 off = v;
1743 }
1744 }
1744 /*
1745 /*
1745 * The node was still not unique after 40 hex digits, so this won't
1746 * The node was still not unique after 40 hex digits, so this won't
1746 * happen. Also, if we get here, then there's a programming error in
1747 * happen. Also, if we get here, then there's a programming error in
1747 * this file that made us insert a node longer than 40 hex digits.
1748 * this file that made us insert a node longer than 40 hex digits.
1748 */
1749 */
1749 PyErr_SetString(PyExc_Exception, "broken node tree");
1750 PyErr_SetString(PyExc_Exception, "broken node tree");
1750 return -3;
1751 return -3;
1751 }
1752 }
1752
1753
1753 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
1754 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
1754 {
1755 {
1755 PyObject *val;
1756 PyObject *val;
1756 char *node;
1757 char *node;
1757 int length;
1758 int length;
1758
1759
1759 if (!PyArg_ParseTuple(args, "O", &val))
1760 if (!PyArg_ParseTuple(args, "O", &val))
1760 return NULL;
1761 return NULL;
1761 if (node_check(val, &node) == -1)
1762 if (node_check(val, &node) == -1)
1762 return NULL;
1763 return NULL;
1763
1764
1764 length = nt_shortest(&self->nt, node);
1765 length = nt_shortest(&self->nt, node);
1765 if (length == -3)
1766 if (length == -3)
1766 return NULL;
1767 return NULL;
1767 if (length == -2) {
1768 if (length == -2) {
1768 raise_revlog_error();
1769 raise_revlog_error();
1769 return NULL;
1770 return NULL;
1770 }
1771 }
1771 return PyInt_FromLong(length);
1772 return PyInt_FromLong(length);
1772 }
1773 }
1773
1774
1774 static void nt_dealloc(nodetree *self)
1775 static void nt_dealloc(nodetree *self)
1775 {
1776 {
1776 free(self->nodes);
1777 free(self->nodes);
1777 self->nodes = NULL;
1778 self->nodes = NULL;
1778 }
1779 }
1779
1780
1780 static void ntobj_dealloc(nodetreeObject *self)
1781 static void ntobj_dealloc(nodetreeObject *self)
1781 {
1782 {
1782 Py_XDECREF(self->nt.index);
1783 Py_XDECREF(self->nt.index);
1783 nt_dealloc(&self->nt);
1784 nt_dealloc(&self->nt);
1784 PyObject_Del(self);
1785 PyObject_Del(self);
1785 }
1786 }
1786
1787
1787 static PyMethodDef ntobj_methods[] = {
1788 static PyMethodDef ntobj_methods[] = {
1788 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
1789 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
1789 "insert an index entry"},
1790 "insert an index entry"},
1790 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
1791 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
1791 "find length of shortest hex nodeid of a binary ID"},
1792 "find length of shortest hex nodeid of a binary ID"},
1792 {NULL} /* Sentinel */
1793 {NULL} /* Sentinel */
1793 };
1794 };
1794
1795
1795 static PyTypeObject nodetreeType = {
1796 static PyTypeObject nodetreeType = {
1796 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1797 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1797 "parsers.nodetree", /* tp_name */
1798 "parsers.nodetree", /* tp_name */
1798 sizeof(nodetreeObject), /* tp_basicsize */
1799 sizeof(nodetreeObject), /* tp_basicsize */
1799 0, /* tp_itemsize */
1800 0, /* tp_itemsize */
1800 (destructor)ntobj_dealloc, /* tp_dealloc */
1801 (destructor)ntobj_dealloc, /* tp_dealloc */
1801 0, /* tp_print */
1802 0, /* tp_print */
1802 0, /* tp_getattr */
1803 0, /* tp_getattr */
1803 0, /* tp_setattr */
1804 0, /* tp_setattr */
1804 0, /* tp_compare */
1805 0, /* tp_compare */
1805 0, /* tp_repr */
1806 0, /* tp_repr */
1806 0, /* tp_as_number */
1807 0, /* tp_as_number */
1807 0, /* tp_as_sequence */
1808 0, /* tp_as_sequence */
1808 0, /* tp_as_mapping */
1809 0, /* tp_as_mapping */
1809 0, /* tp_hash */
1810 0, /* tp_hash */
1810 0, /* tp_call */
1811 0, /* tp_call */
1811 0, /* tp_str */
1812 0, /* tp_str */
1812 0, /* tp_getattro */
1813 0, /* tp_getattro */
1813 0, /* tp_setattro */
1814 0, /* tp_setattro */
1814 0, /* tp_as_buffer */
1815 0, /* tp_as_buffer */
1815 Py_TPFLAGS_DEFAULT, /* tp_flags */
1816 Py_TPFLAGS_DEFAULT, /* tp_flags */
1816 "nodetree", /* tp_doc */
1817 "nodetree", /* tp_doc */
1817 0, /* tp_traverse */
1818 0, /* tp_traverse */
1818 0, /* tp_clear */
1819 0, /* tp_clear */
1819 0, /* tp_richcompare */
1820 0, /* tp_richcompare */
1820 0, /* tp_weaklistoffset */
1821 0, /* tp_weaklistoffset */
1821 0, /* tp_iter */
1822 0, /* tp_iter */
1822 0, /* tp_iternext */
1823 0, /* tp_iternext */
1823 ntobj_methods, /* tp_methods */
1824 ntobj_methods, /* tp_methods */
1824 0, /* tp_members */
1825 0, /* tp_members */
1825 0, /* tp_getset */
1826 0, /* tp_getset */
1826 0, /* tp_base */
1827 0, /* tp_base */
1827 0, /* tp_dict */
1828 0, /* tp_dict */
1828 0, /* tp_descr_get */
1829 0, /* tp_descr_get */
1829 0, /* tp_descr_set */
1830 0, /* tp_descr_set */
1830 0, /* tp_dictoffset */
1831 0, /* tp_dictoffset */
1831 (initproc)ntobj_init, /* tp_init */
1832 (initproc)ntobj_init, /* tp_init */
1832 0, /* tp_alloc */
1833 0, /* tp_alloc */
1833 };
1834 };
1834
1835
1835 static int index_init_nt(indexObject *self)
1836 static int index_init_nt(indexObject *self)
1836 {
1837 {
1837 if (!self->ntinitialized) {
1838 if (!self->ntinitialized) {
1838 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) {
1839 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) {
1839 nt_dealloc(&self->nt);
1840 nt_dealloc(&self->nt);
1840 return -1;
1841 return -1;
1841 }
1842 }
1842 if (nt_insert(&self->nt, nullid, -1) == -1) {
1843 if (nt_insert(&self->nt, nullid, -1) == -1) {
1843 nt_dealloc(&self->nt);
1844 nt_dealloc(&self->nt);
1844 return -1;
1845 return -1;
1845 }
1846 }
1846 self->ntinitialized = 1;
1847 self->ntinitialized = 1;
1847 self->ntrev = (int)index_length(self);
1848 self->ntrev = (int)index_length(self);
1848 self->ntlookups = 1;
1849 self->ntlookups = 1;
1849 self->ntmisses = 0;
1850 self->ntmisses = 0;
1850 }
1851 }
1851 return 0;
1852 return 0;
1852 }
1853 }
1853
1854
1854 /*
1855 /*
1855 * Return values:
1856 * Return values:
1856 *
1857 *
1857 * -3: error (exception set)
1858 * -3: error (exception set)
1858 * -2: not found (no exception set)
1859 * -2: not found (no exception set)
1859 * rest: valid rev
1860 * rest: valid rev
1860 */
1861 */
1861 static int index_find_node(indexObject *self, const char *node,
1862 static int index_find_node(indexObject *self, const char *node,
1862 Py_ssize_t nodelen)
1863 Py_ssize_t nodelen)
1863 {
1864 {
1864 int rev;
1865 int rev;
1865
1866
1866 if (index_init_nt(self) == -1)
1867 if (index_init_nt(self) == -1)
1867 return -3;
1868 return -3;
1868
1869
1869 self->ntlookups++;
1870 self->ntlookups++;
1870 rev = nt_find(&self->nt, node, nodelen, 0);
1871 rev = nt_find(&self->nt, node, nodelen, 0);
1871 if (rev >= -1)
1872 if (rev >= -1)
1872 return rev;
1873 return rev;
1873
1874
1874 /*
1875 /*
1875 * For the first handful of lookups, we scan the entire index,
1876 * For the first handful of lookups, we scan the entire index,
1876 * and cache only the matching nodes. This optimizes for cases
1877 * and cache only the matching nodes. This optimizes for cases
1877 * like "hg tip", where only a few nodes are accessed.
1878 * like "hg tip", where only a few nodes are accessed.
1878 *
1879 *
1879 * After that, we cache every node we visit, using a single
1880 * After that, we cache every node we visit, using a single
1880 * scan amortized over multiple lookups. This gives the best
1881 * scan amortized over multiple lookups. This gives the best
1881 * bulk performance, e.g. for "hg log".
1882 * bulk performance, e.g. for "hg log".
1882 */
1883 */
1883 if (self->ntmisses++ < 4) {
1884 if (self->ntmisses++ < 4) {
1884 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1885 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1885 const char *n = index_node_existing(self, rev);
1886 const char *n = index_node_existing(self, rev);
1886 if (n == NULL)
1887 if (n == NULL)
1887 return -3;
1888 return -3;
1888 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1889 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1889 if (nt_insert(&self->nt, n, rev) == -1)
1890 if (nt_insert(&self->nt, n, rev) == -1)
1890 return -3;
1891 return -3;
1891 break;
1892 break;
1892 }
1893 }
1893 }
1894 }
1894 } else {
1895 } else {
1895 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1896 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1896 const char *n = index_node_existing(self, rev);
1897 const char *n = index_node_existing(self, rev);
1897 if (n == NULL)
1898 if (n == NULL)
1898 return -3;
1899 return -3;
1899 if (nt_insert(&self->nt, n, rev) == -1) {
1900 if (nt_insert(&self->nt, n, rev) == -1) {
1900 self->ntrev = rev + 1;
1901 self->ntrev = rev + 1;
1901 return -3;
1902 return -3;
1902 }
1903 }
1903 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1904 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1904 break;
1905 break;
1905 }
1906 }
1906 }
1907 }
1907 self->ntrev = rev;
1908 self->ntrev = rev;
1908 }
1909 }
1909
1910
1910 if (rev >= 0)
1911 if (rev >= 0)
1911 return rev;
1912 return rev;
1912 return -2;
1913 return -2;
1913 }
1914 }
1914
1915
1915 static PyObject *index_getitem(indexObject *self, PyObject *value)
1916 static PyObject *index_getitem(indexObject *self, PyObject *value)
1916 {
1917 {
1917 char *node;
1918 char *node;
1918 int rev;
1919 int rev;
1919
1920
1920 if (PyInt_Check(value)) {
1921 if (PyInt_Check(value)) {
1921 long idx;
1922 long idx;
1922 if (!pylong_to_long(value, &idx)) {
1923 if (!pylong_to_long(value, &idx)) {
1923 return NULL;
1924 return NULL;
1924 }
1925 }
1925 return index_get(self, idx);
1926 return index_get(self, idx);
1926 }
1927 }
1927
1928
1928 if (node_check(value, &node) == -1)
1929 if (node_check(value, &node) == -1)
1929 return NULL;
1930 return NULL;
1930 rev = index_find_node(self, node, 20);
1931 rev = index_find_node(self, node, 20);
1931 if (rev >= -1)
1932 if (rev >= -1)
1932 return PyInt_FromLong(rev);
1933 return PyInt_FromLong(rev);
1933 if (rev == -2)
1934 if (rev == -2)
1934 raise_revlog_error();
1935 raise_revlog_error();
1935 return NULL;
1936 return NULL;
1936 }
1937 }
1937
1938
1938 /*
1939 /*
1939 * Fully populate the radix tree.
1940 * Fully populate the radix tree.
1940 */
1941 */
1941 static int index_populate_nt(indexObject *self)
1942 static int index_populate_nt(indexObject *self)
1942 {
1943 {
1943 int rev;
1944 int rev;
1944 if (self->ntrev > 0) {
1945 if (self->ntrev > 0) {
1945 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1946 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1946 const char *n = index_node_existing(self, rev);
1947 const char *n = index_node_existing(self, rev);
1947 if (n == NULL)
1948 if (n == NULL)
1948 return -1;
1949 return -1;
1949 if (nt_insert(&self->nt, n, rev) == -1)
1950 if (nt_insert(&self->nt, n, rev) == -1)
1950 return -1;
1951 return -1;
1951 }
1952 }
1952 self->ntrev = -1;
1953 self->ntrev = -1;
1953 }
1954 }
1954 return 0;
1955 return 0;
1955 }
1956 }
1956
1957
1957 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1958 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1958 {
1959 {
1959 const char *fullnode;
1960 const char *fullnode;
1960 Py_ssize_t nodelen;
1961 Py_ssize_t nodelen;
1961 char *node;
1962 char *node;
1962 int rev, i;
1963 int rev, i;
1963
1964
1964 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1965 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1965 return NULL;
1966 return NULL;
1966
1967
1967 if (nodelen < 1) {
1968 if (nodelen < 1) {
1968 PyErr_SetString(PyExc_ValueError, "key too short");
1969 PyErr_SetString(PyExc_ValueError, "key too short");
1969 return NULL;
1970 return NULL;
1970 }
1971 }
1971
1972
1972 if (nodelen > 40) {
1973 if (nodelen > 40) {
1973 PyErr_SetString(PyExc_ValueError, "key too long");
1974 PyErr_SetString(PyExc_ValueError, "key too long");
1974 return NULL;
1975 return NULL;
1975 }
1976 }
1976
1977
1977 for (i = 0; i < nodelen; i++)
1978 for (i = 0; i < nodelen; i++)
1978 hexdigit(node, i);
1979 hexdigit(node, i);
1979 if (PyErr_Occurred()) {
1980 if (PyErr_Occurred()) {
1980 /* input contains non-hex characters */
1981 /* input contains non-hex characters */
1981 PyErr_Clear();
1982 PyErr_Clear();
1982 Py_RETURN_NONE;
1983 Py_RETURN_NONE;
1983 }
1984 }
1984
1985
1985 if (index_init_nt(self) == -1)
1986 if (index_init_nt(self) == -1)
1986 return NULL;
1987 return NULL;
1987 if (index_populate_nt(self) == -1)
1988 if (index_populate_nt(self) == -1)
1988 return NULL;
1989 return NULL;
1989 rev = nt_partialmatch(&self->nt, node, nodelen);
1990 rev = nt_partialmatch(&self->nt, node, nodelen);
1990
1991
1991 switch (rev) {
1992 switch (rev) {
1992 case -4:
1993 case -4:
1993 raise_revlog_error();
1994 raise_revlog_error();
1994 return NULL;
1995 return NULL;
1995 case -2:
1996 case -2:
1996 Py_RETURN_NONE;
1997 Py_RETURN_NONE;
1997 case -1:
1998 case -1:
1998 return PyBytes_FromStringAndSize(nullid, 20);
1999 return PyBytes_FromStringAndSize(nullid, 20);
1999 }
2000 }
2000
2001
2001 fullnode = index_node_existing(self, rev);
2002 fullnode = index_node_existing(self, rev);
2002 if (fullnode == NULL) {
2003 if (fullnode == NULL) {
2003 return NULL;
2004 return NULL;
2004 }
2005 }
2005 return PyBytes_FromStringAndSize(fullnode, 20);
2006 return PyBytes_FromStringAndSize(fullnode, 20);
2006 }
2007 }
2007
2008
2008 static PyObject *index_shortest(indexObject *self, PyObject *args)
2009 static PyObject *index_shortest(indexObject *self, PyObject *args)
2009 {
2010 {
2010 PyObject *val;
2011 PyObject *val;
2011 char *node;
2012 char *node;
2012 int length;
2013 int length;
2013
2014
2014 if (!PyArg_ParseTuple(args, "O", &val))
2015 if (!PyArg_ParseTuple(args, "O", &val))
2015 return NULL;
2016 return NULL;
2016 if (node_check(val, &node) == -1)
2017 if (node_check(val, &node) == -1)
2017 return NULL;
2018 return NULL;
2018
2019
2019 self->ntlookups++;
2020 self->ntlookups++;
2020 if (index_init_nt(self) == -1)
2021 if (index_init_nt(self) == -1)
2021 return NULL;
2022 return NULL;
2022 if (index_populate_nt(self) == -1)
2023 if (index_populate_nt(self) == -1)
2023 return NULL;
2024 return NULL;
2024 length = nt_shortest(&self->nt, node);
2025 length = nt_shortest(&self->nt, node);
2025 if (length == -3)
2026 if (length == -3)
2026 return NULL;
2027 return NULL;
2027 if (length == -2) {
2028 if (length == -2) {
2028 raise_revlog_error();
2029 raise_revlog_error();
2029 return NULL;
2030 return NULL;
2030 }
2031 }
2031 return PyInt_FromLong(length);
2032 return PyInt_FromLong(length);
2032 }
2033 }
2033
2034
2034 static PyObject *index_m_get(indexObject *self, PyObject *args)
2035 static PyObject *index_m_get(indexObject *self, PyObject *args)
2035 {
2036 {
2036 PyObject *val;
2037 PyObject *val;
2037 char *node;
2038 char *node;
2038 int rev;
2039 int rev;
2039
2040
2040 if (!PyArg_ParseTuple(args, "O", &val))
2041 if (!PyArg_ParseTuple(args, "O", &val))
2041 return NULL;
2042 return NULL;
2042 if (node_check(val, &node) == -1)
2043 if (node_check(val, &node) == -1)
2043 return NULL;
2044 return NULL;
2044 rev = index_find_node(self, node, 20);
2045 rev = index_find_node(self, node, 20);
2045 if (rev == -3)
2046 if (rev == -3)
2046 return NULL;
2047 return NULL;
2047 if (rev == -2)
2048 if (rev == -2)
2048 Py_RETURN_NONE;
2049 Py_RETURN_NONE;
2049 return PyInt_FromLong(rev);
2050 return PyInt_FromLong(rev);
2050 }
2051 }
2051
2052
2052 static int index_contains(indexObject *self, PyObject *value)
2053 static int index_contains(indexObject *self, PyObject *value)
2053 {
2054 {
2054 char *node;
2055 char *node;
2055
2056
2056 if (PyInt_Check(value)) {
2057 if (PyInt_Check(value)) {
2057 long rev;
2058 long rev;
2058 if (!pylong_to_long(value, &rev)) {
2059 if (!pylong_to_long(value, &rev)) {
2059 return -1;
2060 return -1;
2060 }
2061 }
2061 return rev >= -1 && rev < index_length(self);
2062 return rev >= -1 && rev < index_length(self);
2062 }
2063 }
2063
2064
2064 if (node_check(value, &node) == -1)
2065 if (node_check(value, &node) == -1)
2065 return -1;
2066 return -1;
2066
2067
2067 switch (index_find_node(self, node, 20)) {
2068 switch (index_find_node(self, node, 20)) {
2068 case -3:
2069 case -3:
2069 return -1;
2070 return -1;
2070 case -2:
2071 case -2:
2071 return 0;
2072 return 0;
2072 default:
2073 default:
2073 return 1;
2074 return 1;
2074 }
2075 }
2075 }
2076 }
2076
2077
2077 static PyObject *index_m_has_node(indexObject *self, PyObject *args)
2078 static PyObject *index_m_has_node(indexObject *self, PyObject *args)
2078 {
2079 {
2079 int ret = index_contains(self, args);
2080 int ret = index_contains(self, args);
2080 if (ret < 0)
2081 if (ret < 0)
2081 return NULL;
2082 return NULL;
2082 return PyBool_FromLong((long)ret);
2083 return PyBool_FromLong((long)ret);
2083 }
2084 }
2084
2085
2085 static PyObject *index_m_rev(indexObject *self, PyObject *val)
2086 static PyObject *index_m_rev(indexObject *self, PyObject *val)
2086 {
2087 {
2087 char *node;
2088 char *node;
2088 int rev;
2089 int rev;
2089
2090
2090 if (node_check(val, &node) == -1)
2091 if (node_check(val, &node) == -1)
2091 return NULL;
2092 return NULL;
2092 rev = index_find_node(self, node, 20);
2093 rev = index_find_node(self, node, 20);
2093 if (rev >= -1)
2094 if (rev >= -1)
2094 return PyInt_FromLong(rev);
2095 return PyInt_FromLong(rev);
2095 if (rev == -2)
2096 if (rev == -2)
2096 raise_revlog_error();
2097 raise_revlog_error();
2097 return NULL;
2098 return NULL;
2098 }
2099 }
2099
2100
2100 typedef uint64_t bitmask;
2101 typedef uint64_t bitmask;
2101
2102
2102 /*
2103 /*
2103 * Given a disjoint set of revs, return all candidates for the
2104 * Given a disjoint set of revs, return all candidates for the
2104 * greatest common ancestor. In revset notation, this is the set
2105 * greatest common ancestor. In revset notation, this is the set
2105 * "heads(::a and ::b and ...)"
2106 * "heads(::a and ::b and ...)"
2106 */
2107 */
2107 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
2108 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
2108 int revcount)
2109 int revcount)
2109 {
2110 {
2110 const bitmask allseen = (1ull << revcount) - 1;
2111 const bitmask allseen = (1ull << revcount) - 1;
2111 const bitmask poison = 1ull << revcount;
2112 const bitmask poison = 1ull << revcount;
2112 PyObject *gca = PyList_New(0);
2113 PyObject *gca = PyList_New(0);
2113 int i, v, interesting;
2114 int i, v, interesting;
2114 int maxrev = -1;
2115 int maxrev = -1;
2115 bitmask sp;
2116 bitmask sp;
2116 bitmask *seen;
2117 bitmask *seen;
2117
2118
2118 if (gca == NULL)
2119 if (gca == NULL)
2119 return PyErr_NoMemory();
2120 return PyErr_NoMemory();
2120
2121
2121 for (i = 0; i < revcount; i++) {
2122 for (i = 0; i < revcount; i++) {
2122 if (revs[i] > maxrev)
2123 if (revs[i] > maxrev)
2123 maxrev = revs[i];
2124 maxrev = revs[i];
2124 }
2125 }
2125
2126
2126 seen = calloc(sizeof(*seen), maxrev + 1);
2127 seen = calloc(sizeof(*seen), maxrev + 1);
2127 if (seen == NULL) {
2128 if (seen == NULL) {
2128 Py_DECREF(gca);
2129 Py_DECREF(gca);
2129 return PyErr_NoMemory();
2130 return PyErr_NoMemory();
2130 }
2131 }
2131
2132
2132 for (i = 0; i < revcount; i++)
2133 for (i = 0; i < revcount; i++)
2133 seen[revs[i]] = 1ull << i;
2134 seen[revs[i]] = 1ull << i;
2134
2135
2135 interesting = revcount;
2136 interesting = revcount;
2136
2137
2137 for (v = maxrev; v >= 0 && interesting; v--) {
2138 for (v = maxrev; v >= 0 && interesting; v--) {
2138 bitmask sv = seen[v];
2139 bitmask sv = seen[v];
2139 int parents[2];
2140 int parents[2];
2140
2141
2141 if (!sv)
2142 if (!sv)
2142 continue;
2143 continue;
2143
2144
2144 if (sv < poison) {
2145 if (sv < poison) {
2145 interesting -= 1;
2146 interesting -= 1;
2146 if (sv == allseen) {
2147 if (sv == allseen) {
2147 PyObject *obj = PyInt_FromLong(v);
2148 PyObject *obj = PyInt_FromLong(v);
2148 if (obj == NULL)
2149 if (obj == NULL)
2149 goto bail;
2150 goto bail;
2150 if (PyList_Append(gca, obj) == -1) {
2151 if (PyList_Append(gca, obj) == -1) {
2151 Py_DECREF(obj);
2152 Py_DECREF(obj);
2152 goto bail;
2153 goto bail;
2153 }
2154 }
2154 sv |= poison;
2155 sv |= poison;
2155 for (i = 0; i < revcount; i++) {
2156 for (i = 0; i < revcount; i++) {
2156 if (revs[i] == v)
2157 if (revs[i] == v)
2157 goto done;
2158 goto done;
2158 }
2159 }
2159 }
2160 }
2160 }
2161 }
2161 if (index_get_parents(self, v, parents, maxrev) < 0)
2162 if (index_get_parents(self, v, parents, maxrev) < 0)
2162 goto bail;
2163 goto bail;
2163
2164
2164 for (i = 0; i < 2; i++) {
2165 for (i = 0; i < 2; i++) {
2165 int p = parents[i];
2166 int p = parents[i];
2166 if (p == -1)
2167 if (p == -1)
2167 continue;
2168 continue;
2168 sp = seen[p];
2169 sp = seen[p];
2169 if (sv < poison) {
2170 if (sv < poison) {
2170 if (sp == 0) {
2171 if (sp == 0) {
2171 seen[p] = sv;
2172 seen[p] = sv;
2172 interesting++;
2173 interesting++;
2173 } else if (sp != sv)
2174 } else if (sp != sv)
2174 seen[p] |= sv;
2175 seen[p] |= sv;
2175 } else {
2176 } else {
2176 if (sp && sp < poison)
2177 if (sp && sp < poison)
2177 interesting--;
2178 interesting--;
2178 seen[p] = sv;
2179 seen[p] = sv;
2179 }
2180 }
2180 }
2181 }
2181 }
2182 }
2182
2183
2183 done:
2184 done:
2184 free(seen);
2185 free(seen);
2185 return gca;
2186 return gca;
2186 bail:
2187 bail:
2187 free(seen);
2188 free(seen);
2188 Py_XDECREF(gca);
2189 Py_XDECREF(gca);
2189 return NULL;
2190 return NULL;
2190 }
2191 }
2191
2192
2192 /*
2193 /*
2193 * Given a disjoint set of revs, return the subset with the longest
2194 * Given a disjoint set of revs, return the subset with the longest
2194 * path to the root.
2195 * path to the root.
2195 */
2196 */
2196 static PyObject *find_deepest(indexObject *self, PyObject *revs)
2197 static PyObject *find_deepest(indexObject *self, PyObject *revs)
2197 {
2198 {
2198 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
2199 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
2199 static const Py_ssize_t capacity = 24;
2200 static const Py_ssize_t capacity = 24;
2200 int *depth, *interesting = NULL;
2201 int *depth, *interesting = NULL;
2201 int i, j, v, ninteresting;
2202 int i, j, v, ninteresting;
2202 PyObject *dict = NULL, *keys = NULL;
2203 PyObject *dict = NULL, *keys = NULL;
2203 long *seen = NULL;
2204 long *seen = NULL;
2204 int maxrev = -1;
2205 int maxrev = -1;
2205 long final;
2206 long final;
2206
2207
2207 if (revcount > capacity) {
2208 if (revcount > capacity) {
2208 PyErr_Format(PyExc_OverflowError,
2209 PyErr_Format(PyExc_OverflowError,
2209 "bitset size (%ld) > capacity (%ld)",
2210 "bitset size (%ld) > capacity (%ld)",
2210 (long)revcount, (long)capacity);
2211 (long)revcount, (long)capacity);
2211 return NULL;
2212 return NULL;
2212 }
2213 }
2213
2214
2214 for (i = 0; i < revcount; i++) {
2215 for (i = 0; i < revcount; i++) {
2215 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2216 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2216 if (n > maxrev)
2217 if (n > maxrev)
2217 maxrev = n;
2218 maxrev = n;
2218 }
2219 }
2219
2220
2220 depth = calloc(sizeof(*depth), maxrev + 1);
2221 depth = calloc(sizeof(*depth), maxrev + 1);
2221 if (depth == NULL)
2222 if (depth == NULL)
2222 return PyErr_NoMemory();
2223 return PyErr_NoMemory();
2223
2224
2224 seen = calloc(sizeof(*seen), maxrev + 1);
2225 seen = calloc(sizeof(*seen), maxrev + 1);
2225 if (seen == NULL) {
2226 if (seen == NULL) {
2226 PyErr_NoMemory();
2227 PyErr_NoMemory();
2227 goto bail;
2228 goto bail;
2228 }
2229 }
2229
2230
2230 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2231 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2231 if (interesting == NULL) {
2232 if (interesting == NULL) {
2232 PyErr_NoMemory();
2233 PyErr_NoMemory();
2233 goto bail;
2234 goto bail;
2234 }
2235 }
2235
2236
2236 if (PyList_Sort(revs) == -1)
2237 if (PyList_Sort(revs) == -1)
2237 goto bail;
2238 goto bail;
2238
2239
2239 for (i = 0; i < revcount; i++) {
2240 for (i = 0; i < revcount; i++) {
2240 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2241 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2241 long b = 1l << i;
2242 long b = 1l << i;
2242 depth[n] = 1;
2243 depth[n] = 1;
2243 seen[n] = b;
2244 seen[n] = b;
2244 interesting[b] = 1;
2245 interesting[b] = 1;
2245 }
2246 }
2246
2247
2247 /* invariant: ninteresting is the number of non-zero entries in
2248 /* invariant: ninteresting is the number of non-zero entries in
2248 * interesting. */
2249 * interesting. */
2249 ninteresting = (int)revcount;
2250 ninteresting = (int)revcount;
2250
2251
2251 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2252 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2252 int dv = depth[v];
2253 int dv = depth[v];
2253 int parents[2];
2254 int parents[2];
2254 long sv;
2255 long sv;
2255
2256
2256 if (dv == 0)
2257 if (dv == 0)
2257 continue;
2258 continue;
2258
2259
2259 sv = seen[v];
2260 sv = seen[v];
2260 if (index_get_parents(self, v, parents, maxrev) < 0)
2261 if (index_get_parents(self, v, parents, maxrev) < 0)
2261 goto bail;
2262 goto bail;
2262
2263
2263 for (i = 0; i < 2; i++) {
2264 for (i = 0; i < 2; i++) {
2264 int p = parents[i];
2265 int p = parents[i];
2265 long sp;
2266 long sp;
2266 int dp;
2267 int dp;
2267
2268
2268 if (p == -1)
2269 if (p == -1)
2269 continue;
2270 continue;
2270
2271
2271 dp = depth[p];
2272 dp = depth[p];
2272 sp = seen[p];
2273 sp = seen[p];
2273 if (dp <= dv) {
2274 if (dp <= dv) {
2274 depth[p] = dv + 1;
2275 depth[p] = dv + 1;
2275 if (sp != sv) {
2276 if (sp != sv) {
2276 interesting[sv] += 1;
2277 interesting[sv] += 1;
2277 seen[p] = sv;
2278 seen[p] = sv;
2278 if (sp) {
2279 if (sp) {
2279 interesting[sp] -= 1;
2280 interesting[sp] -= 1;
2280 if (interesting[sp] == 0)
2281 if (interesting[sp] == 0)
2281 ninteresting -= 1;
2282 ninteresting -= 1;
2282 }
2283 }
2283 }
2284 }
2284 } else if (dv == dp - 1) {
2285 } else if (dv == dp - 1) {
2285 long nsp = sp | sv;
2286 long nsp = sp | sv;
2286 if (nsp == sp)
2287 if (nsp == sp)
2287 continue;
2288 continue;
2288 seen[p] = nsp;
2289 seen[p] = nsp;
2289 interesting[sp] -= 1;
2290 interesting[sp] -= 1;
2290 if (interesting[sp] == 0)
2291 if (interesting[sp] == 0)
2291 ninteresting -= 1;
2292 ninteresting -= 1;
2292 if (interesting[nsp] == 0)
2293 if (interesting[nsp] == 0)
2293 ninteresting += 1;
2294 ninteresting += 1;
2294 interesting[nsp] += 1;
2295 interesting[nsp] += 1;
2295 }
2296 }
2296 }
2297 }
2297 interesting[sv] -= 1;
2298 interesting[sv] -= 1;
2298 if (interesting[sv] == 0)
2299 if (interesting[sv] == 0)
2299 ninteresting -= 1;
2300 ninteresting -= 1;
2300 }
2301 }
2301
2302
2302 final = 0;
2303 final = 0;
2303 j = ninteresting;
2304 j = ninteresting;
2304 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2305 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2305 if (interesting[i] == 0)
2306 if (interesting[i] == 0)
2306 continue;
2307 continue;
2307 final |= i;
2308 final |= i;
2308 j -= 1;
2309 j -= 1;
2309 }
2310 }
2310 if (final == 0) {
2311 if (final == 0) {
2311 keys = PyList_New(0);
2312 keys = PyList_New(0);
2312 goto bail;
2313 goto bail;
2313 }
2314 }
2314
2315
2315 dict = PyDict_New();
2316 dict = PyDict_New();
2316 if (dict == NULL)
2317 if (dict == NULL)
2317 goto bail;
2318 goto bail;
2318
2319
2319 for (i = 0; i < revcount; i++) {
2320 for (i = 0; i < revcount; i++) {
2320 PyObject *key;
2321 PyObject *key;
2321
2322
2322 if ((final & (1 << i)) == 0)
2323 if ((final & (1 << i)) == 0)
2323 continue;
2324 continue;
2324
2325
2325 key = PyList_GET_ITEM(revs, i);
2326 key = PyList_GET_ITEM(revs, i);
2326 Py_INCREF(key);
2327 Py_INCREF(key);
2327 Py_INCREF(Py_None);
2328 Py_INCREF(Py_None);
2328 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2329 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2329 Py_DECREF(key);
2330 Py_DECREF(key);
2330 Py_DECREF(Py_None);
2331 Py_DECREF(Py_None);
2331 goto bail;
2332 goto bail;
2332 }
2333 }
2333 }
2334 }
2334
2335
2335 keys = PyDict_Keys(dict);
2336 keys = PyDict_Keys(dict);
2336
2337
2337 bail:
2338 bail:
2338 free(depth);
2339 free(depth);
2339 free(seen);
2340 free(seen);
2340 free(interesting);
2341 free(interesting);
2341 Py_XDECREF(dict);
2342 Py_XDECREF(dict);
2342
2343
2343 return keys;
2344 return keys;
2344 }
2345 }
2345
2346
2346 /*
2347 /*
2347 * Given a (possibly overlapping) set of revs, return all the
2348 * Given a (possibly overlapping) set of revs, return all the
2348 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2349 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2349 */
2350 */
2350 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2351 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2351 {
2352 {
2352 PyObject *ret = NULL;
2353 PyObject *ret = NULL;
2353 Py_ssize_t argcount, i, len;
2354 Py_ssize_t argcount, i, len;
2354 bitmask repeat = 0;
2355 bitmask repeat = 0;
2355 int revcount = 0;
2356 int revcount = 0;
2356 int *revs;
2357 int *revs;
2357
2358
2358 argcount = PySequence_Length(args);
2359 argcount = PySequence_Length(args);
2359 revs = PyMem_Malloc(argcount * sizeof(*revs));
2360 revs = PyMem_Malloc(argcount * sizeof(*revs));
2360 if (argcount > 0 && revs == NULL)
2361 if (argcount > 0 && revs == NULL)
2361 return PyErr_NoMemory();
2362 return PyErr_NoMemory();
2362 len = index_length(self);
2363 len = index_length(self);
2363
2364
2364 for (i = 0; i < argcount; i++) {
2365 for (i = 0; i < argcount; i++) {
2365 static const int capacity = 24;
2366 static const int capacity = 24;
2366 PyObject *obj = PySequence_GetItem(args, i);
2367 PyObject *obj = PySequence_GetItem(args, i);
2367 bitmask x;
2368 bitmask x;
2368 long val;
2369 long val;
2369
2370
2370 if (!PyInt_Check(obj)) {
2371 if (!PyInt_Check(obj)) {
2371 PyErr_SetString(PyExc_TypeError,
2372 PyErr_SetString(PyExc_TypeError,
2372 "arguments must all be ints");
2373 "arguments must all be ints");
2373 Py_DECREF(obj);
2374 Py_DECREF(obj);
2374 goto bail;
2375 goto bail;
2375 }
2376 }
2376 val = PyInt_AsLong(obj);
2377 val = PyInt_AsLong(obj);
2377 Py_DECREF(obj);
2378 Py_DECREF(obj);
2378 if (val == -1) {
2379 if (val == -1) {
2379 ret = PyList_New(0);
2380 ret = PyList_New(0);
2380 goto done;
2381 goto done;
2381 }
2382 }
2382 if (val < 0 || val >= len) {
2383 if (val < 0 || val >= len) {
2383 PyErr_SetString(PyExc_IndexError, "index out of range");
2384 PyErr_SetString(PyExc_IndexError, "index out of range");
2384 goto bail;
2385 goto bail;
2385 }
2386 }
2386 /* this cheesy bloom filter lets us avoid some more
2387 /* this cheesy bloom filter lets us avoid some more
2387 * expensive duplicate checks in the common set-is-disjoint
2388 * expensive duplicate checks in the common set-is-disjoint
2388 * case */
2389 * case */
2389 x = 1ull << (val & 0x3f);
2390 x = 1ull << (val & 0x3f);
2390 if (repeat & x) {
2391 if (repeat & x) {
2391 int k;
2392 int k;
2392 for (k = 0; k < revcount; k++) {
2393 for (k = 0; k < revcount; k++) {
2393 if (val == revs[k])
2394 if (val == revs[k])
2394 goto duplicate;
2395 goto duplicate;
2395 }
2396 }
2396 } else
2397 } else
2397 repeat |= x;
2398 repeat |= x;
2398 if (revcount >= capacity) {
2399 if (revcount >= capacity) {
2399 PyErr_Format(PyExc_OverflowError,
2400 PyErr_Format(PyExc_OverflowError,
2400 "bitset size (%d) > capacity (%d)",
2401 "bitset size (%d) > capacity (%d)",
2401 revcount, capacity);
2402 revcount, capacity);
2402 goto bail;
2403 goto bail;
2403 }
2404 }
2404 revs[revcount++] = (int)val;
2405 revs[revcount++] = (int)val;
2405 duplicate:;
2406 duplicate:;
2406 }
2407 }
2407
2408
2408 if (revcount == 0) {
2409 if (revcount == 0) {
2409 ret = PyList_New(0);
2410 ret = PyList_New(0);
2410 goto done;
2411 goto done;
2411 }
2412 }
2412 if (revcount == 1) {
2413 if (revcount == 1) {
2413 PyObject *obj;
2414 PyObject *obj;
2414 ret = PyList_New(1);
2415 ret = PyList_New(1);
2415 if (ret == NULL)
2416 if (ret == NULL)
2416 goto bail;
2417 goto bail;
2417 obj = PyInt_FromLong(revs[0]);
2418 obj = PyInt_FromLong(revs[0]);
2418 if (obj == NULL)
2419 if (obj == NULL)
2419 goto bail;
2420 goto bail;
2420 PyList_SET_ITEM(ret, 0, obj);
2421 PyList_SET_ITEM(ret, 0, obj);
2421 goto done;
2422 goto done;
2422 }
2423 }
2423
2424
2424 ret = find_gca_candidates(self, revs, revcount);
2425 ret = find_gca_candidates(self, revs, revcount);
2425 if (ret == NULL)
2426 if (ret == NULL)
2426 goto bail;
2427 goto bail;
2427
2428
2428 done:
2429 done:
2429 PyMem_Free(revs);
2430 PyMem_Free(revs);
2430 return ret;
2431 return ret;
2431
2432
2432 bail:
2433 bail:
2433 PyMem_Free(revs);
2434 PyMem_Free(revs);
2434 Py_XDECREF(ret);
2435 Py_XDECREF(ret);
2435 return NULL;
2436 return NULL;
2436 }
2437 }
2437
2438
2438 /*
2439 /*
2439 * Given a (possibly overlapping) set of revs, return the greatest
2440 * Given a (possibly overlapping) set of revs, return the greatest
2440 * common ancestors: those with the longest path to the root.
2441 * common ancestors: those with the longest path to the root.
2441 */
2442 */
2442 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2443 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2443 {
2444 {
2444 PyObject *ret;
2445 PyObject *ret;
2445 PyObject *gca = index_commonancestorsheads(self, args);
2446 PyObject *gca = index_commonancestorsheads(self, args);
2446 if (gca == NULL)
2447 if (gca == NULL)
2447 return NULL;
2448 return NULL;
2448
2449
2449 if (PyList_GET_SIZE(gca) <= 1) {
2450 if (PyList_GET_SIZE(gca) <= 1) {
2450 return gca;
2451 return gca;
2451 }
2452 }
2452
2453
2453 ret = find_deepest(self, gca);
2454 ret = find_deepest(self, gca);
2454 Py_DECREF(gca);
2455 Py_DECREF(gca);
2455 return ret;
2456 return ret;
2456 }
2457 }
2457
2458
2458 /*
2459 /*
2459 * Invalidate any trie entries introduced by added revs.
2460 * Invalidate any trie entries introduced by added revs.
2460 */
2461 */
2461 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2462 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2462 {
2463 {
2463 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2464 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2464
2465
2465 for (i = start; i < len; i++) {
2466 for (i = start; i < len; i++) {
2466 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2467 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2467 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2468 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2468
2469
2469 nt_delete_node(&self->nt, PyBytes_AS_STRING(node));
2470 nt_delete_node(&self->nt, PyBytes_AS_STRING(node));
2470 }
2471 }
2471
2472
2472 if (start == 0)
2473 if (start == 0)
2473 Py_CLEAR(self->added);
2474 Py_CLEAR(self->added);
2474 }
2475 }
2475
2476
2476 /*
2477 /*
2477 * Delete a numeric range of revs, which must be at the end of the
2478 * Delete a numeric range of revs, which must be at the end of the
2478 * range.
2479 * range.
2479 */
2480 */
2480 static int index_slice_del(indexObject *self, PyObject *item)
2481 static int index_slice_del(indexObject *self, PyObject *item)
2481 {
2482 {
2482 Py_ssize_t start, stop, step, slicelength;
2483 Py_ssize_t start, stop, step, slicelength;
2483 Py_ssize_t length = index_length(self) + 1;
2484 Py_ssize_t length = index_length(self) + 1;
2484 int ret = 0;
2485 int ret = 0;
2485
2486
2486 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
2487 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
2487 #ifdef IS_PY3K
2488 #ifdef IS_PY3K
2488 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2489 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2489 &slicelength) < 0)
2490 &slicelength) < 0)
2490 #else
2491 #else
2491 if (PySlice_GetIndicesEx((PySliceObject *)item, length, &start, &stop,
2492 if (PySlice_GetIndicesEx((PySliceObject *)item, length, &start, &stop,
2492 &step, &slicelength) < 0)
2493 &step, &slicelength) < 0)
2493 #endif
2494 #endif
2494 return -1;
2495 return -1;
2495
2496
2496 if (slicelength <= 0)
2497 if (slicelength <= 0)
2497 return 0;
2498 return 0;
2498
2499
2499 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2500 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2500 stop = start;
2501 stop = start;
2501
2502
2502 if (step < 0) {
2503 if (step < 0) {
2503 stop = start + 1;
2504 stop = start + 1;
2504 start = stop + step * (slicelength - 1) - 1;
2505 start = stop + step * (slicelength - 1) - 1;
2505 step = -step;
2506 step = -step;
2506 }
2507 }
2507
2508
2508 if (step != 1) {
2509 if (step != 1) {
2509 PyErr_SetString(PyExc_ValueError,
2510 PyErr_SetString(PyExc_ValueError,
2510 "revlog index delete requires step size of 1");
2511 "revlog index delete requires step size of 1");
2511 return -1;
2512 return -1;
2512 }
2513 }
2513
2514
2514 if (stop != length - 1) {
2515 if (stop != length - 1) {
2515 PyErr_SetString(PyExc_IndexError,
2516 PyErr_SetString(PyExc_IndexError,
2516 "revlog index deletion indices are invalid");
2517 "revlog index deletion indices are invalid");
2517 return -1;
2518 return -1;
2518 }
2519 }
2519
2520
2520 if (start < self->length) {
2521 if (start < self->length) {
2521 if (self->ntinitialized) {
2522 if (self->ntinitialized) {
2522 Py_ssize_t i;
2523 Py_ssize_t i;
2523
2524
2524 for (i = start; i < self->length; i++) {
2525 for (i = start; i < self->length; i++) {
2525 const char *node = index_node_existing(self, i);
2526 const char *node = index_node_existing(self, i);
2526 if (node == NULL)
2527 if (node == NULL)
2527 return -1;
2528 return -1;
2528
2529
2529 nt_delete_node(&self->nt, node);
2530 nt_delete_node(&self->nt, node);
2530 }
2531 }
2531 if (self->added)
2532 if (self->added)
2532 index_invalidate_added(self, 0);
2533 index_invalidate_added(self, 0);
2533 if (self->ntrev > start)
2534 if (self->ntrev > start)
2534 self->ntrev = (int)start;
2535 self->ntrev = (int)start;
2535 } else if (self->added) {
2536 } else if (self->added) {
2536 Py_CLEAR(self->added);
2537 Py_CLEAR(self->added);
2537 }
2538 }
2538
2539
2539 self->length = start;
2540 self->length = start;
2540 if (start < self->raw_length) {
2541 if (start < self->raw_length) {
2541 if (self->cache) {
2542 if (self->cache) {
2542 Py_ssize_t i;
2543 Py_ssize_t i;
2543 for (i = start; i < self->raw_length; i++)
2544 for (i = start; i < self->raw_length; i++)
2544 Py_CLEAR(self->cache[i]);
2545 Py_CLEAR(self->cache[i]);
2545 }
2546 }
2546 self->raw_length = start;
2547 self->raw_length = start;
2547 }
2548 }
2548 goto done;
2549 goto done;
2549 }
2550 }
2550
2551
2551 if (self->ntinitialized) {
2552 if (self->ntinitialized) {
2552 index_invalidate_added(self, start - self->length);
2553 index_invalidate_added(self, start - self->length);
2553 if (self->ntrev > start)
2554 if (self->ntrev > start)
2554 self->ntrev = (int)start;
2555 self->ntrev = (int)start;
2555 }
2556 }
2556 if (self->added)
2557 if (self->added)
2557 ret = PyList_SetSlice(self->added, start - self->length,
2558 ret = PyList_SetSlice(self->added, start - self->length,
2558 PyList_GET_SIZE(self->added), NULL);
2559 PyList_GET_SIZE(self->added), NULL);
2559 done:
2560 done:
2560 Py_CLEAR(self->headrevs);
2561 Py_CLEAR(self->headrevs);
2561 return ret;
2562 return ret;
2562 }
2563 }
2563
2564
2564 /*
2565 /*
2565 * Supported ops:
2566 * Supported ops:
2566 *
2567 *
2567 * slice deletion
2568 * slice deletion
2568 * string assignment (extend node->rev mapping)
2569 * string assignment (extend node->rev mapping)
2569 * string deletion (shrink node->rev mapping)
2570 * string deletion (shrink node->rev mapping)
2570 */
2571 */
2571 static int index_assign_subscript(indexObject *self, PyObject *item,
2572 static int index_assign_subscript(indexObject *self, PyObject *item,
2572 PyObject *value)
2573 PyObject *value)
2573 {
2574 {
2574 char *node;
2575 char *node;
2575 long rev;
2576 long rev;
2576
2577
2577 if (PySlice_Check(item) && value == NULL)
2578 if (PySlice_Check(item) && value == NULL)
2578 return index_slice_del(self, item);
2579 return index_slice_del(self, item);
2579
2580
2580 if (node_check(item, &node) == -1)
2581 if (node_check(item, &node) == -1)
2581 return -1;
2582 return -1;
2582
2583
2583 if (value == NULL)
2584 if (value == NULL)
2584 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2585 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2585 : 0;
2586 : 0;
2586 rev = PyInt_AsLong(value);
2587 rev = PyInt_AsLong(value);
2587 if (rev > INT_MAX || rev < 0) {
2588 if (rev > INT_MAX || rev < 0) {
2588 if (!PyErr_Occurred())
2589 if (!PyErr_Occurred())
2589 PyErr_SetString(PyExc_ValueError, "rev out of range");
2590 PyErr_SetString(PyExc_ValueError, "rev out of range");
2590 return -1;
2591 return -1;
2591 }
2592 }
2592
2593
2593 if (index_init_nt(self) == -1)
2594 if (index_init_nt(self) == -1)
2594 return -1;
2595 return -1;
2595 return nt_insert(&self->nt, node, (int)rev);
2596 return nt_insert(&self->nt, node, (int)rev);
2596 }
2597 }
2597
2598
2598 /*
2599 /*
2599 * Find all RevlogNG entries in an index that has inline data. Update
2600 * Find all RevlogNG entries in an index that has inline data. Update
2600 * the optional "offsets" table with those entries.
2601 * the optional "offsets" table with those entries.
2601 */
2602 */
2602 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2603 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2603 {
2604 {
2604 const char *data = (const char *)self->buf.buf;
2605 const char *data = (const char *)self->buf.buf;
2605 Py_ssize_t pos = 0;
2606 Py_ssize_t pos = 0;
2606 Py_ssize_t end = self->buf.len;
2607 Py_ssize_t end = self->buf.len;
2607 long incr = v1_hdrsize;
2608 long incr = v1_hdrsize;
2608 Py_ssize_t len = 0;
2609 Py_ssize_t len = 0;
2609
2610
2610 while (pos + v1_hdrsize <= end && pos >= 0) {
2611 while (pos + v1_hdrsize <= end && pos >= 0) {
2611 uint32_t comp_len;
2612 uint32_t comp_len;
2612 /* 3rd element of header is length of compressed inline data */
2613 /* 3rd element of header is length of compressed inline data */
2613 comp_len = getbe32(data + pos + 8);
2614 comp_len = getbe32(data + pos + 8);
2614 incr = v1_hdrsize + comp_len;
2615 incr = v1_hdrsize + comp_len;
2615 if (offsets)
2616 if (offsets)
2616 offsets[len] = data + pos;
2617 offsets[len] = data + pos;
2617 len++;
2618 len++;
2618 pos += incr;
2619 pos += incr;
2619 }
2620 }
2620
2621
2621 if (pos != end) {
2622 if (pos != end) {
2622 if (!PyErr_Occurred())
2623 if (!PyErr_Occurred())
2623 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2624 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2624 return -1;
2625 return -1;
2625 }
2626 }
2626
2627
2627 return len;
2628 return len;
2628 }
2629 }
2629
2630
2630 static int index_init(indexObject *self, PyObject *args)
2631 static int index_init(indexObject *self, PyObject *args)
2631 {
2632 {
2632 PyObject *data_obj, *inlined_obj;
2633 PyObject *data_obj, *inlined_obj;
2633 Py_ssize_t size;
2634 Py_ssize_t size;
2634
2635
2635 /* Initialize before argument-checking to avoid index_dealloc() crash.
2636 /* Initialize before argument-checking to avoid index_dealloc() crash.
2636 */
2637 */
2637 self->raw_length = 0;
2638 self->raw_length = 0;
2638 self->added = NULL;
2639 self->added = NULL;
2639 self->cache = NULL;
2640 self->cache = NULL;
2640 self->data = NULL;
2641 self->data = NULL;
2641 memset(&self->buf, 0, sizeof(self->buf));
2642 memset(&self->buf, 0, sizeof(self->buf));
2642 self->headrevs = NULL;
2643 self->headrevs = NULL;
2643 self->filteredrevs = Py_None;
2644 self->filteredrevs = Py_None;
2644 Py_INCREF(Py_None);
2645 Py_INCREF(Py_None);
2645 self->ntinitialized = 0;
2646 self->ntinitialized = 0;
2646 self->offsets = NULL;
2647 self->offsets = NULL;
2647
2648
2648 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2649 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2649 return -1;
2650 return -1;
2650 if (!PyObject_CheckBuffer(data_obj)) {
2651 if (!PyObject_CheckBuffer(data_obj)) {
2651 PyErr_SetString(PyExc_TypeError,
2652 PyErr_SetString(PyExc_TypeError,
2652 "data does not support buffer interface");
2653 "data does not support buffer interface");
2653 return -1;
2654 return -1;
2654 }
2655 }
2655
2656
2656 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
2657 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
2657 return -1;
2658 return -1;
2658 size = self->buf.len;
2659 size = self->buf.len;
2659
2660
2660 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2661 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2661 self->data = data_obj;
2662 self->data = data_obj;
2662
2663
2663 self->ntlookups = self->ntmisses = 0;
2664 self->ntlookups = self->ntmisses = 0;
2664 self->ntrev = -1;
2665 self->ntrev = -1;
2665 Py_INCREF(self->data);
2666 Py_INCREF(self->data);
2666
2667
2667 if (self->inlined) {
2668 if (self->inlined) {
2668 Py_ssize_t len = inline_scan(self, NULL);
2669 Py_ssize_t len = inline_scan(self, NULL);
2669 if (len == -1)
2670 if (len == -1)
2670 goto bail;
2671 goto bail;
2671 self->raw_length = len;
2672 self->raw_length = len;
2672 self->length = len;
2673 self->length = len;
2673 } else {
2674 } else {
2674 if (size % v1_hdrsize) {
2675 if (size % v1_hdrsize) {
2675 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2676 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2676 goto bail;
2677 goto bail;
2677 }
2678 }
2678 self->raw_length = size / v1_hdrsize;
2679 self->raw_length = size / v1_hdrsize;
2679 self->length = self->raw_length;
2680 self->length = self->raw_length;
2680 }
2681 }
2681
2682
2682 return 0;
2683 return 0;
2683 bail:
2684 bail:
2684 return -1;
2685 return -1;
2685 }
2686 }
2686
2687
2687 static PyObject *index_nodemap(indexObject *self)
2688 static PyObject *index_nodemap(indexObject *self)
2688 {
2689 {
2689 Py_INCREF(self);
2690 Py_INCREF(self);
2690 return (PyObject *)self;
2691 return (PyObject *)self;
2691 }
2692 }
2692
2693
2693 static void _index_clearcaches(indexObject *self)
2694 static void _index_clearcaches(indexObject *self)
2694 {
2695 {
2695 if (self->cache) {
2696 if (self->cache) {
2696 Py_ssize_t i;
2697 Py_ssize_t i;
2697
2698
2698 for (i = 0; i < self->raw_length; i++)
2699 for (i = 0; i < self->raw_length; i++)
2699 Py_CLEAR(self->cache[i]);
2700 Py_CLEAR(self->cache[i]);
2700 free(self->cache);
2701 free(self->cache);
2701 self->cache = NULL;
2702 self->cache = NULL;
2702 }
2703 }
2703 if (self->offsets) {
2704 if (self->offsets) {
2704 PyMem_Free((void *)self->offsets);
2705 PyMem_Free((void *)self->offsets);
2705 self->offsets = NULL;
2706 self->offsets = NULL;
2706 }
2707 }
2707 if (self->ntinitialized) {
2708 if (self->ntinitialized) {
2708 nt_dealloc(&self->nt);
2709 nt_dealloc(&self->nt);
2709 }
2710 }
2710 self->ntinitialized = 0;
2711 self->ntinitialized = 0;
2711 Py_CLEAR(self->headrevs);
2712 Py_CLEAR(self->headrevs);
2712 }
2713 }
2713
2714
2714 static PyObject *index_clearcaches(indexObject *self)
2715 static PyObject *index_clearcaches(indexObject *self)
2715 {
2716 {
2716 _index_clearcaches(self);
2717 _index_clearcaches(self);
2717 self->ntrev = -1;
2718 self->ntrev = -1;
2718 self->ntlookups = self->ntmisses = 0;
2719 self->ntlookups = self->ntmisses = 0;
2719 Py_RETURN_NONE;
2720 Py_RETURN_NONE;
2720 }
2721 }
2721
2722
2722 static void index_dealloc(indexObject *self)
2723 static void index_dealloc(indexObject *self)
2723 {
2724 {
2724 _index_clearcaches(self);
2725 _index_clearcaches(self);
2725 Py_XDECREF(self->filteredrevs);
2726 Py_XDECREF(self->filteredrevs);
2726 if (self->buf.buf) {
2727 if (self->buf.buf) {
2727 PyBuffer_Release(&self->buf);
2728 PyBuffer_Release(&self->buf);
2728 memset(&self->buf, 0, sizeof(self->buf));
2729 memset(&self->buf, 0, sizeof(self->buf));
2729 }
2730 }
2730 Py_XDECREF(self->data);
2731 Py_XDECREF(self->data);
2731 Py_XDECREF(self->added);
2732 Py_XDECREF(self->added);
2732 PyObject_Del(self);
2733 PyObject_Del(self);
2733 }
2734 }
2734
2735
2735 static PySequenceMethods index_sequence_methods = {
2736 static PySequenceMethods index_sequence_methods = {
2736 (lenfunc)index_length, /* sq_length */
2737 (lenfunc)index_length, /* sq_length */
2737 0, /* sq_concat */
2738 0, /* sq_concat */
2738 0, /* sq_repeat */
2739 0, /* sq_repeat */
2739 (ssizeargfunc)index_get, /* sq_item */
2740 (ssizeargfunc)index_get, /* sq_item */
2740 0, /* sq_slice */
2741 0, /* sq_slice */
2741 0, /* sq_ass_item */
2742 0, /* sq_ass_item */
2742 0, /* sq_ass_slice */
2743 0, /* sq_ass_slice */
2743 (objobjproc)index_contains, /* sq_contains */
2744 (objobjproc)index_contains, /* sq_contains */
2744 };
2745 };
2745
2746
2746 static PyMappingMethods index_mapping_methods = {
2747 static PyMappingMethods index_mapping_methods = {
2747 (lenfunc)index_length, /* mp_length */
2748 (lenfunc)index_length, /* mp_length */
2748 (binaryfunc)index_getitem, /* mp_subscript */
2749 (binaryfunc)index_getitem, /* mp_subscript */
2749 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2750 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2750 };
2751 };
2751
2752
2752 static PyMethodDef index_methods[] = {
2753 static PyMethodDef index_methods[] = {
2753 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2754 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2754 "return the gca set of the given revs"},
2755 "return the gca set of the given revs"},
2755 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2756 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2756 METH_VARARGS,
2757 METH_VARARGS,
2757 "return the heads of the common ancestors of the given revs"},
2758 "return the heads of the common ancestors of the given revs"},
2758 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2759 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2759 "clear the index caches"},
2760 "clear the index caches"},
2760 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
2761 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
2761 {"get_rev", (PyCFunction)index_m_get, METH_VARARGS,
2762 {"get_rev", (PyCFunction)index_m_get, METH_VARARGS,
2762 "return `rev` associated with a node or None"},
2763 "return `rev` associated with a node or None"},
2763 {"has_node", (PyCFunction)index_m_has_node, METH_O,
2764 {"has_node", (PyCFunction)index_m_has_node, METH_O,
2764 "return True if the node exist in the index"},
2765 "return True if the node exist in the index"},
2765 {"rev", (PyCFunction)index_m_rev, METH_O,
2766 {"rev", (PyCFunction)index_m_rev, METH_O,
2766 "return `rev` associated with a node or raise RevlogError"},
2767 "return `rev` associated with a node or raise RevlogError"},
2767 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
2768 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
2768 "compute phases"},
2769 "compute phases"},
2769 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2770 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2770 "reachableroots"},
2771 "reachableroots"},
2771 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2772 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2772 "get head revisions"}, /* Can do filtering since 3.2 */
2773 "get head revisions"}, /* Can do filtering since 3.2 */
2773 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2774 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2774 "get filtered head revisions"}, /* Can always do filtering */
2775 "get filtered head revisions"}, /* Can always do filtering */
2775 {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
2776 {"issnapshot", (PyCFunction)index_issnapshot, METH_O,
2776 "True if the object is a snapshot"},
2777 "True if the object is a snapshot"},
2777 {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
2778 {"findsnapshots", (PyCFunction)index_findsnapshots, METH_VARARGS,
2778 "Gather snapshot data in a cache dict"},
2779 "Gather snapshot data in a cache dict"},
2779 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2780 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2780 "determine revisions with deltas to reconstruct fulltext"},
2781 "determine revisions with deltas to reconstruct fulltext"},
2781 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
2782 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
2782 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
2783 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
2783 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
2784 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
2784 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2785 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2785 "match a potentially ambiguous node ID"},
2786 "match a potentially ambiguous node ID"},
2786 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2787 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2787 "find length of shortest hex nodeid of a binary ID"},
2788 "find length of shortest hex nodeid of a binary ID"},
2788 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
2789 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
2789 {NULL} /* Sentinel */
2790 {NULL} /* Sentinel */
2790 };
2791 };
2791
2792
2792 static PyGetSetDef index_getset[] = {
2793 static PyGetSetDef index_getset[] = {
2793 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2794 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2794 {NULL} /* Sentinel */
2795 {NULL} /* Sentinel */
2795 };
2796 };
2796
2797
2797 PyTypeObject HgRevlogIndex_Type = {
2798 PyTypeObject HgRevlogIndex_Type = {
2798 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2799 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2799 "parsers.index", /* tp_name */
2800 "parsers.index", /* tp_name */
2800 sizeof(indexObject), /* tp_basicsize */
2801 sizeof(indexObject), /* tp_basicsize */
2801 0, /* tp_itemsize */
2802 0, /* tp_itemsize */
2802 (destructor)index_dealloc, /* tp_dealloc */
2803 (destructor)index_dealloc, /* tp_dealloc */
2803 0, /* tp_print */
2804 0, /* tp_print */
2804 0, /* tp_getattr */
2805 0, /* tp_getattr */
2805 0, /* tp_setattr */
2806 0, /* tp_setattr */
2806 0, /* tp_compare */
2807 0, /* tp_compare */
2807 0, /* tp_repr */
2808 0, /* tp_repr */
2808 0, /* tp_as_number */
2809 0, /* tp_as_number */
2809 &index_sequence_methods, /* tp_as_sequence */
2810 &index_sequence_methods, /* tp_as_sequence */
2810 &index_mapping_methods, /* tp_as_mapping */
2811 &index_mapping_methods, /* tp_as_mapping */
2811 0, /* tp_hash */
2812 0, /* tp_hash */
2812 0, /* tp_call */
2813 0, /* tp_call */
2813 0, /* tp_str */
2814 0, /* tp_str */
2814 0, /* tp_getattro */
2815 0, /* tp_getattro */
2815 0, /* tp_setattro */
2816 0, /* tp_setattro */
2816 0, /* tp_as_buffer */
2817 0, /* tp_as_buffer */
2817 Py_TPFLAGS_DEFAULT, /* tp_flags */
2818 Py_TPFLAGS_DEFAULT, /* tp_flags */
2818 "revlog index", /* tp_doc */
2819 "revlog index", /* tp_doc */
2819 0, /* tp_traverse */
2820 0, /* tp_traverse */
2820 0, /* tp_clear */
2821 0, /* tp_clear */
2821 0, /* tp_richcompare */
2822 0, /* tp_richcompare */
2822 0, /* tp_weaklistoffset */
2823 0, /* tp_weaklistoffset */
2823 0, /* tp_iter */
2824 0, /* tp_iter */
2824 0, /* tp_iternext */
2825 0, /* tp_iternext */
2825 index_methods, /* tp_methods */
2826 index_methods, /* tp_methods */
2826 0, /* tp_members */
2827 0, /* tp_members */
2827 index_getset, /* tp_getset */
2828 index_getset, /* tp_getset */
2828 0, /* tp_base */
2829 0, /* tp_base */
2829 0, /* tp_dict */
2830 0, /* tp_dict */
2830 0, /* tp_descr_get */
2831 0, /* tp_descr_get */
2831 0, /* tp_descr_set */
2832 0, /* tp_descr_set */
2832 0, /* tp_dictoffset */
2833 0, /* tp_dictoffset */
2833 (initproc)index_init, /* tp_init */
2834 (initproc)index_init, /* tp_init */
2834 0, /* tp_alloc */
2835 0, /* tp_alloc */
2835 };
2836 };
2836
2837
2837 /*
2838 /*
2838 * returns a tuple of the form (index, index, cache) with elements as
2839 * returns a tuple of the form (index, index, cache) with elements as
2839 * follows:
2840 * follows:
2840 *
2841 *
2841 * index: an index object that lazily parses RevlogNG records
2842 * index: an index object that lazily parses RevlogNG records
2842 * cache: if data is inlined, a tuple (0, index_file_content), else None
2843 * cache: if data is inlined, a tuple (0, index_file_content), else None
2843 * index_file_content could be a string, or a buffer
2844 * index_file_content could be a string, or a buffer
2844 *
2845 *
2845 * added complications are for backwards compatibility
2846 * added complications are for backwards compatibility
2846 */
2847 */
2847 PyObject *parse_index2(PyObject *self, PyObject *args)
2848 PyObject *parse_index2(PyObject *self, PyObject *args)
2848 {
2849 {
2849 PyObject *tuple = NULL, *cache = NULL;
2850 PyObject *tuple = NULL, *cache = NULL;
2850 indexObject *idx;
2851 indexObject *idx;
2851 int ret;
2852 int ret;
2852
2853
2853 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
2854 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
2854 if (idx == NULL)
2855 if (idx == NULL)
2855 goto bail;
2856 goto bail;
2856
2857
2857 ret = index_init(idx, args);
2858 ret = index_init(idx, args);
2858 if (ret == -1)
2859 if (ret == -1)
2859 goto bail;
2860 goto bail;
2860
2861
2861 if (idx->inlined) {
2862 if (idx->inlined) {
2862 cache = Py_BuildValue("iO", 0, idx->data);
2863 cache = Py_BuildValue("iO", 0, idx->data);
2863 if (cache == NULL)
2864 if (cache == NULL)
2864 goto bail;
2865 goto bail;
2865 } else {
2866 } else {
2866 cache = Py_None;
2867 cache = Py_None;
2867 Py_INCREF(cache);
2868 Py_INCREF(cache);
2868 }
2869 }
2869
2870
2870 tuple = Py_BuildValue("NN", idx, cache);
2871 tuple = Py_BuildValue("NN", idx, cache);
2871 if (!tuple)
2872 if (!tuple)
2872 goto bail;
2873 goto bail;
2873 return tuple;
2874 return tuple;
2874
2875
2875 bail:
2876 bail:
2876 Py_XDECREF(idx);
2877 Py_XDECREF(idx);
2877 Py_XDECREF(cache);
2878 Py_XDECREF(cache);
2878 Py_XDECREF(tuple);
2879 Py_XDECREF(tuple);
2879 return NULL;
2880 return NULL;
2880 }
2881 }
2881
2882
2882 static Revlog_CAPI CAPI = {
2883 static Revlog_CAPI CAPI = {
2883 /* increment the abi_version field upon each change in the Revlog_CAPI
2884 /* increment the abi_version field upon each change in the Revlog_CAPI
2884 struct or in the ABI of the listed functions */
2885 struct or in the ABI of the listed functions */
2885 2,
2886 2,
2886 index_length,
2887 index_length,
2887 index_node,
2888 index_node,
2888 HgRevlogIndex_GetParents,
2889 HgRevlogIndex_GetParents,
2889 };
2890 };
2890
2891
2891 void revlog_module_init(PyObject *mod)
2892 void revlog_module_init(PyObject *mod)
2892 {
2893 {
2893 PyObject *caps = NULL;
2894 PyObject *caps = NULL;
2894 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
2895 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
2895 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
2896 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
2896 return;
2897 return;
2897 Py_INCREF(&HgRevlogIndex_Type);
2898 Py_INCREF(&HgRevlogIndex_Type);
2898 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
2899 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
2899
2900
2900 nodetreeType.tp_new = PyType_GenericNew;
2901 nodetreeType.tp_new = PyType_GenericNew;
2901 if (PyType_Ready(&nodetreeType) < 0)
2902 if (PyType_Ready(&nodetreeType) < 0)
2902 return;
2903 return;
2903 Py_INCREF(&nodetreeType);
2904 Py_INCREF(&nodetreeType);
2904 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
2905 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
2905
2906
2906 if (!nullentry) {
2907 if (!nullentry) {
2907 nullentry =
2908 nullentry =
2908 Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, -1,
2909 Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, -1,
2909 -1, -1, -1, nullid, (Py_ssize_t)20);
2910 -1, -1, -1, nullid, (Py_ssize_t)20);
2910 }
2911 }
2911 if (nullentry)
2912 if (nullentry)
2912 PyObject_GC_UnTrack(nullentry);
2913 PyObject_GC_UnTrack(nullentry);
2913
2914
2914 caps = PyCapsule_New(&CAPI, "mercurial.cext.parsers.revlog_CAPI", NULL);
2915 caps = PyCapsule_New(&CAPI, "mercurial.cext.parsers.revlog_CAPI", NULL);
2915 if (caps != NULL)
2916 if (caps != NULL)
2916 PyModule_AddObject(mod, "revlog_CAPI", caps);
2917 PyModule_AddObject(mod, "revlog_CAPI", caps);
2917 }
2918 }
General Comments 0
You need to be logged in to leave comments. Login now