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