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