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