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