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