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