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