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