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