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