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