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