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