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