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