##// END OF EJS Templates
parsers: remove no longer used dirstate_unset
Siddharth Agarwal -
r21807:a96a3d12 default
parent child Browse files
Show More
@@ -1,2087 +1,2083 b''
1 1 /*
2 2 parsers.c - efficient content parsing
3 3
4 4 Copyright 2008 Matt Mackall <mpm@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 #include <Python.h>
11 11 #include <ctype.h>
12 12 #include <stddef.h>
13 13 #include <string.h>
14 14
15 15 #include "util.h"
16 16
17 17 static char *versionerrortext = "Python minor version mismatch";
18 18
19 19 static int8_t hextable[256] = {
20 20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 36 };
37 37
38 38 static inline int hexdigit(const char *p, Py_ssize_t off)
39 39 {
40 40 int8_t val = hextable[(unsigned char)p[off]];
41 41
42 42 if (val >= 0) {
43 43 return val;
44 44 }
45 45
46 46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
47 47 return 0;
48 48 }
49 49
50 50 /*
51 51 * Turn a hex-encoded string into binary.
52 52 */
53 53 static PyObject *unhexlify(const char *str, int len)
54 54 {
55 55 PyObject *ret;
56 56 char *d;
57 57 int i;
58 58
59 59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
60 60
61 61 if (!ret)
62 62 return NULL;
63 63
64 64 d = PyBytes_AsString(ret);
65 65
66 66 for (i = 0; i < len;) {
67 67 int hi = hexdigit(str, i++);
68 68 int lo = hexdigit(str, i++);
69 69 *d++ = (hi << 4) | lo;
70 70 }
71 71
72 72 return ret;
73 73 }
74 74
75 75 /*
76 76 * This code assumes that a manifest is stitched together with newline
77 77 * ('\n') characters.
78 78 */
79 79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
80 80 {
81 81 PyObject *mfdict, *fdict;
82 82 char *str, *start, *end;
83 83 int len;
84 84
85 85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
86 86 &PyDict_Type, &mfdict,
87 87 &PyDict_Type, &fdict,
88 88 &str, &len))
89 89 goto quit;
90 90
91 91 start = str;
92 92 end = str + len;
93 93 while (start < end) {
94 94 PyObject *file = NULL, *node = NULL;
95 95 PyObject *flags = NULL;
96 96 char *zero = NULL, *newline = NULL;
97 97 ptrdiff_t nlen;
98 98
99 99 zero = memchr(start, '\0', end - start);
100 100 if (!zero) {
101 101 PyErr_SetString(PyExc_ValueError,
102 102 "manifest entry has no separator");
103 103 goto quit;
104 104 }
105 105
106 106 newline = memchr(zero + 1, '\n', end - (zero + 1));
107 107 if (!newline) {
108 108 PyErr_SetString(PyExc_ValueError,
109 109 "manifest contains trailing garbage");
110 110 goto quit;
111 111 }
112 112
113 113 file = PyBytes_FromStringAndSize(start, zero - start);
114 114
115 115 if (!file)
116 116 goto bail;
117 117
118 118 nlen = newline - zero - 1;
119 119
120 120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
121 121 if (!node)
122 122 goto bail;
123 123
124 124 if (nlen > 40) {
125 125 flags = PyBytes_FromStringAndSize(zero + 41,
126 126 nlen - 40);
127 127 if (!flags)
128 128 goto bail;
129 129
130 130 if (PyDict_SetItem(fdict, file, flags) == -1)
131 131 goto bail;
132 132 }
133 133
134 134 if (PyDict_SetItem(mfdict, file, node) == -1)
135 135 goto bail;
136 136
137 137 start = newline + 1;
138 138
139 139 Py_XDECREF(flags);
140 140 Py_XDECREF(node);
141 141 Py_XDECREF(file);
142 142 continue;
143 143 bail:
144 144 Py_XDECREF(flags);
145 145 Py_XDECREF(node);
146 146 Py_XDECREF(file);
147 147 goto quit;
148 148 }
149 149
150 150 Py_INCREF(Py_None);
151 151 return Py_None;
152 152 quit:
153 153 return NULL;
154 154 }
155 155
156 156 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
157 157 {
158 158 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
159 159 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
160 160 char state, *cur, *str, *cpos;
161 161 int mode, size, mtime;
162 162 unsigned int flen;
163 163 int len, pos = 40;
164 164
165 165 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
166 166 &PyDict_Type, &dmap,
167 167 &PyDict_Type, &cmap,
168 168 &str, &len))
169 169 goto quit;
170 170
171 171 /* read parents */
172 172 if (len < 40)
173 173 goto quit;
174 174
175 175 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
176 176 if (!parents)
177 177 goto quit;
178 178
179 179 /* read filenames */
180 180 while (pos >= 40 && pos < len) {
181 181 cur = str + pos;
182 182 /* unpack header */
183 183 state = *cur;
184 184 mode = getbe32(cur + 1);
185 185 size = getbe32(cur + 5);
186 186 mtime = getbe32(cur + 9);
187 187 flen = getbe32(cur + 13);
188 188 pos += 17;
189 189 cur += 17;
190 190 if (flen > len - pos) {
191 191 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
192 192 goto quit;
193 193 }
194 194
195 195 entry = Py_BuildValue("ciii", state, mode, size, mtime);
196 196 if (!entry)
197 197 goto quit;
198 198 PyObject_GC_UnTrack(entry); /* don't waste time with this */
199 199
200 200 cpos = memchr(cur, 0, flen);
201 201 if (cpos) {
202 202 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
203 203 cname = PyBytes_FromStringAndSize(cpos + 1,
204 204 flen - (cpos - cur) - 1);
205 205 if (!fname || !cname ||
206 206 PyDict_SetItem(cmap, fname, cname) == -1 ||
207 207 PyDict_SetItem(dmap, fname, entry) == -1)
208 208 goto quit;
209 209 Py_DECREF(cname);
210 210 } else {
211 211 fname = PyBytes_FromStringAndSize(cur, flen);
212 212 if (!fname ||
213 213 PyDict_SetItem(dmap, fname, entry) == -1)
214 214 goto quit;
215 215 }
216 216 Py_DECREF(fname);
217 217 Py_DECREF(entry);
218 218 fname = cname = entry = NULL;
219 219 pos += flen;
220 220 }
221 221
222 222 ret = parents;
223 223 Py_INCREF(ret);
224 224 quit:
225 225 Py_XDECREF(fname);
226 226 Py_XDECREF(cname);
227 227 Py_XDECREF(entry);
228 228 Py_XDECREF(parents);
229 229 return ret;
230 230 }
231 231
232 232 static inline int getintat(PyObject *tuple, int off, uint32_t *v)
233 233 {
234 234 PyObject *o = PyTuple_GET_ITEM(tuple, off);
235 235 long val;
236 236
237 237 if (PyInt_Check(o))
238 238 val = PyInt_AS_LONG(o);
239 239 else if (PyLong_Check(o)) {
240 240 val = PyLong_AsLong(o);
241 241 if (val == -1 && PyErr_Occurred())
242 242 return -1;
243 243 } else {
244 244 PyErr_SetString(PyExc_TypeError, "expected an int or long");
245 245 return -1;
246 246 }
247 247 if (LONG_MAX > INT_MAX && (val > INT_MAX || val < INT_MIN)) {
248 248 PyErr_SetString(PyExc_OverflowError,
249 249 "Python value to large to convert to uint32_t");
250 250 return -1;
251 251 }
252 252 *v = (uint32_t)val;
253 253 return 0;
254 254 }
255 255
256 static PyObject *dirstate_unset;
257
258 256 /*
259 257 * Efficiently pack a dirstate object into its on-disk format.
260 258 */
261 259 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
262 260 {
263 261 PyObject *packobj = NULL;
264 262 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
265 263 Py_ssize_t nbytes, pos, l;
266 264 PyObject *k, *v, *pn;
267 265 char *p, *s;
268 266 double now;
269 267
270 268 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
271 269 &PyDict_Type, &map, &PyDict_Type, &copymap,
272 270 &pl, &now))
273 271 return NULL;
274 272
275 273 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
276 274 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
277 275 return NULL;
278 276 }
279 277
280 278 /* Figure out how much we need to allocate. */
281 279 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
282 280 PyObject *c;
283 281 if (!PyString_Check(k)) {
284 282 PyErr_SetString(PyExc_TypeError, "expected string key");
285 283 goto bail;
286 284 }
287 285 nbytes += PyString_GET_SIZE(k) + 17;
288 286 c = PyDict_GetItem(copymap, k);
289 287 if (c) {
290 288 if (!PyString_Check(c)) {
291 289 PyErr_SetString(PyExc_TypeError,
292 290 "expected string key");
293 291 goto bail;
294 292 }
295 293 nbytes += PyString_GET_SIZE(c) + 1;
296 294 }
297 295 }
298 296
299 297 packobj = PyString_FromStringAndSize(NULL, nbytes);
300 298 if (packobj == NULL)
301 299 goto bail;
302 300
303 301 p = PyString_AS_STRING(packobj);
304 302
305 303 pn = PySequence_ITEM(pl, 0);
306 304 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
307 305 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
308 306 goto bail;
309 307 }
310 308 memcpy(p, s, l);
311 309 p += 20;
312 310 pn = PySequence_ITEM(pl, 1);
313 311 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
314 312 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
315 313 goto bail;
316 314 }
317 315 memcpy(p, s, l);
318 316 p += 20;
319 317
320 318 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
321 319 uint32_t mode, size, mtime;
322 320 Py_ssize_t len, l;
323 321 PyObject *o;
324 322 char *s, *t;
325 323
326 324 if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) {
327 325 PyErr_SetString(PyExc_TypeError, "expected a 4-tuple");
328 326 goto bail;
329 327 }
330 328 o = PyTuple_GET_ITEM(v, 0);
331 329 if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) {
332 330 PyErr_SetString(PyExc_TypeError, "expected one byte");
333 331 goto bail;
334 332 }
335 333 *p++ = *s;
336 334 if (getintat(v, 1, &mode) == -1)
337 335 goto bail;
338 336 if (getintat(v, 2, &size) == -1)
339 337 goto bail;
340 338 if (getintat(v, 3, &mtime) == -1)
341 339 goto bail;
342 340 if (*s == 'n' && mtime == (uint32_t)now) {
343 341 /* See pure/parsers.py:pack_dirstate for why we do
344 342 * this. */
345 343 mtime = -1;
346 344 mtime_unset = Py_BuildValue(
347 345 "ciii", *s, mode, size, mtime);
348 346 if (!mtime_unset)
349 347 goto bail;
350 348 if (PyDict_SetItem(map, k, mtime_unset) == -1)
351 349 goto bail;
352 350 Py_DECREF(mtime_unset);
353 351 mtime_unset = NULL;
354 352 }
355 353 putbe32(mode, p);
356 354 putbe32(size, p + 4);
357 355 putbe32(mtime, p + 8);
358 356 t = p + 12;
359 357 p += 16;
360 358 len = PyString_GET_SIZE(k);
361 359 memcpy(p, PyString_AS_STRING(k), len);
362 360 p += len;
363 361 o = PyDict_GetItem(copymap, k);
364 362 if (o) {
365 363 *p++ = '\0';
366 364 l = PyString_GET_SIZE(o);
367 365 memcpy(p, PyString_AS_STRING(o), l);
368 366 p += l;
369 367 len += l + 1;
370 368 }
371 369 putbe32((uint32_t)len, t);
372 370 }
373 371
374 372 pos = p - PyString_AS_STRING(packobj);
375 373 if (pos != nbytes) {
376 374 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
377 375 (long)pos, (long)nbytes);
378 376 goto bail;
379 377 }
380 378
381 379 return packobj;
382 380 bail:
383 381 Py_XDECREF(mtime_unset);
384 382 Py_XDECREF(packobj);
385 383 return NULL;
386 384 }
387 385
388 386 /*
389 387 * A base-16 trie for fast node->rev mapping.
390 388 *
391 389 * Positive value is index of the next node in the trie
392 390 * Negative value is a leaf: -(rev + 1)
393 391 * Zero is empty
394 392 */
395 393 typedef struct {
396 394 int children[16];
397 395 } nodetree;
398 396
399 397 /*
400 398 * This class has two behaviours.
401 399 *
402 400 * When used in a list-like way (with integer keys), we decode an
403 401 * entry in a RevlogNG index file on demand. Our last entry is a
404 402 * sentinel, always a nullid. We have limited support for
405 403 * integer-keyed insert and delete, only at elements right before the
406 404 * sentinel.
407 405 *
408 406 * With string keys, we lazily perform a reverse mapping from node to
409 407 * rev, using a base-16 trie.
410 408 */
411 409 typedef struct {
412 410 PyObject_HEAD
413 411 /* Type-specific fields go here. */
414 412 PyObject *data; /* raw bytes of index */
415 413 PyObject **cache; /* cached tuples */
416 414 const char **offsets; /* populated on demand */
417 415 Py_ssize_t raw_length; /* original number of elements */
418 416 Py_ssize_t length; /* current number of elements */
419 417 PyObject *added; /* populated on demand */
420 418 PyObject *headrevs; /* cache, invalidated on changes */
421 419 nodetree *nt; /* base-16 trie */
422 420 int ntlength; /* # nodes in use */
423 421 int ntcapacity; /* # nodes allocated */
424 422 int ntdepth; /* maximum depth of tree */
425 423 int ntsplits; /* # splits performed */
426 424 int ntrev; /* last rev scanned */
427 425 int ntlookups; /* # lookups */
428 426 int ntmisses; /* # lookups that miss the cache */
429 427 int inlined;
430 428 } indexObject;
431 429
432 430 static Py_ssize_t index_length(const indexObject *self)
433 431 {
434 432 if (self->added == NULL)
435 433 return self->length;
436 434 return self->length + PyList_GET_SIZE(self->added);
437 435 }
438 436
439 437 static PyObject *nullentry;
440 438 static const char nullid[20];
441 439
442 440 static long inline_scan(indexObject *self, const char **offsets);
443 441
444 442 #if LONG_MAX == 0x7fffffffL
445 443 static char *tuple_format = "Kiiiiiis#";
446 444 #else
447 445 static char *tuple_format = "kiiiiiis#";
448 446 #endif
449 447
450 448 /* A RevlogNG v1 index entry is 64 bytes long. */
451 449 static const long v1_hdrsize = 64;
452 450
453 451 /*
454 452 * Return a pointer to the beginning of a RevlogNG record.
455 453 */
456 454 static const char *index_deref(indexObject *self, Py_ssize_t pos)
457 455 {
458 456 if (self->inlined && pos > 0) {
459 457 if (self->offsets == NULL) {
460 458 self->offsets = malloc(self->raw_length *
461 459 sizeof(*self->offsets));
462 460 if (self->offsets == NULL)
463 461 return (const char *)PyErr_NoMemory();
464 462 inline_scan(self, self->offsets);
465 463 }
466 464 return self->offsets[pos];
467 465 }
468 466
469 467 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
470 468 }
471 469
472 470 /*
473 471 * RevlogNG format (all in big endian, data may be inlined):
474 472 * 6 bytes: offset
475 473 * 2 bytes: flags
476 474 * 4 bytes: compressed length
477 475 * 4 bytes: uncompressed length
478 476 * 4 bytes: base revision
479 477 * 4 bytes: link revision
480 478 * 4 bytes: parent 1 revision
481 479 * 4 bytes: parent 2 revision
482 480 * 32 bytes: nodeid (only 20 bytes used)
483 481 */
484 482 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
485 483 {
486 484 uint64_t offset_flags;
487 485 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
488 486 const char *c_node_id;
489 487 const char *data;
490 488 Py_ssize_t length = index_length(self);
491 489 PyObject *entry;
492 490
493 491 if (pos < 0)
494 492 pos += length;
495 493
496 494 if (pos < 0 || pos >= length) {
497 495 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
498 496 return NULL;
499 497 }
500 498
501 499 if (pos == length - 1) {
502 500 Py_INCREF(nullentry);
503 501 return nullentry;
504 502 }
505 503
506 504 if (pos >= self->length - 1) {
507 505 PyObject *obj;
508 506 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
509 507 Py_INCREF(obj);
510 508 return obj;
511 509 }
512 510
513 511 if (self->cache) {
514 512 if (self->cache[pos]) {
515 513 Py_INCREF(self->cache[pos]);
516 514 return self->cache[pos];
517 515 }
518 516 } else {
519 517 self->cache = calloc(self->raw_length, sizeof(PyObject *));
520 518 if (self->cache == NULL)
521 519 return PyErr_NoMemory();
522 520 }
523 521
524 522 data = index_deref(self, pos);
525 523 if (data == NULL)
526 524 return NULL;
527 525
528 526 offset_flags = getbe32(data + 4);
529 527 if (pos == 0) /* mask out version number for the first entry */
530 528 offset_flags &= 0xFFFF;
531 529 else {
532 530 uint32_t offset_high = getbe32(data);
533 531 offset_flags |= ((uint64_t)offset_high) << 32;
534 532 }
535 533
536 534 comp_len = getbe32(data + 8);
537 535 uncomp_len = getbe32(data + 12);
538 536 base_rev = getbe32(data + 16);
539 537 link_rev = getbe32(data + 20);
540 538 parent_1 = getbe32(data + 24);
541 539 parent_2 = getbe32(data + 28);
542 540 c_node_id = data + 32;
543 541
544 542 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
545 543 uncomp_len, base_rev, link_rev,
546 544 parent_1, parent_2, c_node_id, 20);
547 545
548 546 if (entry) {
549 547 PyObject_GC_UnTrack(entry);
550 548 Py_INCREF(entry);
551 549 }
552 550
553 551 self->cache[pos] = entry;
554 552
555 553 return entry;
556 554 }
557 555
558 556 /*
559 557 * Return the 20-byte SHA of the node corresponding to the given rev.
560 558 */
561 559 static const char *index_node(indexObject *self, Py_ssize_t pos)
562 560 {
563 561 Py_ssize_t length = index_length(self);
564 562 const char *data;
565 563
566 564 if (pos == length - 1 || pos == INT_MAX)
567 565 return nullid;
568 566
569 567 if (pos >= length)
570 568 return NULL;
571 569
572 570 if (pos >= self->length - 1) {
573 571 PyObject *tuple, *str;
574 572 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
575 573 str = PyTuple_GetItem(tuple, 7);
576 574 return str ? PyString_AS_STRING(str) : NULL;
577 575 }
578 576
579 577 data = index_deref(self, pos);
580 578 return data ? data + 32 : NULL;
581 579 }
582 580
583 581 static int nt_insert(indexObject *self, const char *node, int rev);
584 582
585 583 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
586 584 {
587 585 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
588 586 return -1;
589 587 if (*nodelen == 20)
590 588 return 0;
591 589 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
592 590 return -1;
593 591 }
594 592
595 593 static PyObject *index_insert(indexObject *self, PyObject *args)
596 594 {
597 595 PyObject *obj;
598 596 char *node;
599 597 long offset;
600 598 Py_ssize_t len, nodelen;
601 599
602 600 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
603 601 return NULL;
604 602
605 603 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
606 604 PyErr_SetString(PyExc_TypeError, "8-tuple required");
607 605 return NULL;
608 606 }
609 607
610 608 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
611 609 return NULL;
612 610
613 611 len = index_length(self);
614 612
615 613 if (offset < 0)
616 614 offset += len;
617 615
618 616 if (offset != len - 1) {
619 617 PyErr_SetString(PyExc_IndexError,
620 618 "insert only supported at index -1");
621 619 return NULL;
622 620 }
623 621
624 622 if (offset > INT_MAX) {
625 623 PyErr_SetString(PyExc_ValueError,
626 624 "currently only 2**31 revs supported");
627 625 return NULL;
628 626 }
629 627
630 628 if (self->added == NULL) {
631 629 self->added = PyList_New(0);
632 630 if (self->added == NULL)
633 631 return NULL;
634 632 }
635 633
636 634 if (PyList_Append(self->added, obj) == -1)
637 635 return NULL;
638 636
639 637 if (self->nt)
640 638 nt_insert(self, node, (int)offset);
641 639
642 640 Py_CLEAR(self->headrevs);
643 641 Py_RETURN_NONE;
644 642 }
645 643
646 644 static void _index_clearcaches(indexObject *self)
647 645 {
648 646 if (self->cache) {
649 647 Py_ssize_t i;
650 648
651 649 for (i = 0; i < self->raw_length; i++)
652 650 Py_CLEAR(self->cache[i]);
653 651 free(self->cache);
654 652 self->cache = NULL;
655 653 }
656 654 if (self->offsets) {
657 655 free(self->offsets);
658 656 self->offsets = NULL;
659 657 }
660 658 if (self->nt) {
661 659 free(self->nt);
662 660 self->nt = NULL;
663 661 }
664 662 Py_CLEAR(self->headrevs);
665 663 }
666 664
667 665 static PyObject *index_clearcaches(indexObject *self)
668 666 {
669 667 _index_clearcaches(self);
670 668 self->ntlength = self->ntcapacity = 0;
671 669 self->ntdepth = self->ntsplits = 0;
672 670 self->ntrev = -1;
673 671 self->ntlookups = self->ntmisses = 0;
674 672 Py_RETURN_NONE;
675 673 }
676 674
677 675 static PyObject *index_stats(indexObject *self)
678 676 {
679 677 PyObject *obj = PyDict_New();
680 678
681 679 if (obj == NULL)
682 680 return NULL;
683 681
684 682 #define istat(__n, __d) \
685 683 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
686 684 goto bail;
687 685
688 686 if (self->added) {
689 687 Py_ssize_t len = PyList_GET_SIZE(self->added);
690 688 if (PyDict_SetItemString(obj, "index entries added",
691 689 PyInt_FromSsize_t(len)) == -1)
692 690 goto bail;
693 691 }
694 692
695 693 if (self->raw_length != self->length - 1)
696 694 istat(raw_length, "revs on disk");
697 695 istat(length, "revs in memory");
698 696 istat(ntcapacity, "node trie capacity");
699 697 istat(ntdepth, "node trie depth");
700 698 istat(ntlength, "node trie count");
701 699 istat(ntlookups, "node trie lookups");
702 700 istat(ntmisses, "node trie misses");
703 701 istat(ntrev, "node trie last rev scanned");
704 702 istat(ntsplits, "node trie splits");
705 703
706 704 #undef istat
707 705
708 706 return obj;
709 707
710 708 bail:
711 709 Py_XDECREF(obj);
712 710 return NULL;
713 711 }
714 712
715 713 /*
716 714 * When we cache a list, we want to be sure the caller can't mutate
717 715 * the cached copy.
718 716 */
719 717 static PyObject *list_copy(PyObject *list)
720 718 {
721 719 Py_ssize_t len = PyList_GET_SIZE(list);
722 720 PyObject *newlist = PyList_New(len);
723 721 Py_ssize_t i;
724 722
725 723 if (newlist == NULL)
726 724 return NULL;
727 725
728 726 for (i = 0; i < len; i++) {
729 727 PyObject *obj = PyList_GET_ITEM(list, i);
730 728 Py_INCREF(obj);
731 729 PyList_SET_ITEM(newlist, i, obj);
732 730 }
733 731
734 732 return newlist;
735 733 }
736 734
737 735 static PyObject *index_headrevs(indexObject *self)
738 736 {
739 737 Py_ssize_t i, len, addlen;
740 738 char *nothead = NULL;
741 739 PyObject *heads;
742 740
743 741 if (self->headrevs)
744 742 return list_copy(self->headrevs);
745 743
746 744 len = index_length(self) - 1;
747 745 heads = PyList_New(0);
748 746 if (heads == NULL)
749 747 goto bail;
750 748 if (len == 0) {
751 749 PyObject *nullid = PyInt_FromLong(-1);
752 750 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
753 751 Py_XDECREF(nullid);
754 752 goto bail;
755 753 }
756 754 goto done;
757 755 }
758 756
759 757 nothead = calloc(len, 1);
760 758 if (nothead == NULL)
761 759 goto bail;
762 760
763 761 for (i = 0; i < self->raw_length; i++) {
764 762 const char *data = index_deref(self, i);
765 763 int parent_1 = getbe32(data + 24);
766 764 int parent_2 = getbe32(data + 28);
767 765 if (parent_1 >= 0)
768 766 nothead[parent_1] = 1;
769 767 if (parent_2 >= 0)
770 768 nothead[parent_2] = 1;
771 769 }
772 770
773 771 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
774 772
775 773 for (i = 0; i < addlen; i++) {
776 774 PyObject *rev = PyList_GET_ITEM(self->added, i);
777 775 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
778 776 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
779 777 long parent_1, parent_2;
780 778
781 779 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
782 780 PyErr_SetString(PyExc_TypeError,
783 781 "revlog parents are invalid");
784 782 goto bail;
785 783 }
786 784 parent_1 = PyInt_AS_LONG(p1);
787 785 parent_2 = PyInt_AS_LONG(p2);
788 786 if (parent_1 >= 0)
789 787 nothead[parent_1] = 1;
790 788 if (parent_2 >= 0)
791 789 nothead[parent_2] = 1;
792 790 }
793 791
794 792 for (i = 0; i < len; i++) {
795 793 PyObject *head;
796 794
797 795 if (nothead[i])
798 796 continue;
799 797 head = PyInt_FromLong(i);
800 798 if (head == NULL || PyList_Append(heads, head) == -1) {
801 799 Py_XDECREF(head);
802 800 goto bail;
803 801 }
804 802 }
805 803
806 804 done:
807 805 self->headrevs = heads;
808 806 free(nothead);
809 807 return list_copy(self->headrevs);
810 808 bail:
811 809 Py_XDECREF(heads);
812 810 free(nothead);
813 811 return NULL;
814 812 }
815 813
816 814 static inline int nt_level(const char *node, Py_ssize_t level)
817 815 {
818 816 int v = node[level>>1];
819 817 if (!(level & 1))
820 818 v >>= 4;
821 819 return v & 0xf;
822 820 }
823 821
824 822 /*
825 823 * Return values:
826 824 *
827 825 * -4: match is ambiguous (multiple candidates)
828 826 * -2: not found
829 827 * rest: valid rev
830 828 */
831 829 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
832 830 int hex)
833 831 {
834 832 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
835 833 int level, maxlevel, off;
836 834
837 835 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
838 836 return -1;
839 837
840 838 if (self->nt == NULL)
841 839 return -2;
842 840
843 841 if (hex)
844 842 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
845 843 else
846 844 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
847 845
848 846 for (level = off = 0; level < maxlevel; level++) {
849 847 int k = getnybble(node, level);
850 848 nodetree *n = &self->nt[off];
851 849 int v = n->children[k];
852 850
853 851 if (v < 0) {
854 852 const char *n;
855 853 Py_ssize_t i;
856 854
857 855 v = -v - 1;
858 856 n = index_node(self, v);
859 857 if (n == NULL)
860 858 return -2;
861 859 for (i = level; i < maxlevel; i++)
862 860 if (getnybble(node, i) != nt_level(n, i))
863 861 return -2;
864 862 return v;
865 863 }
866 864 if (v == 0)
867 865 return -2;
868 866 off = v;
869 867 }
870 868 /* multiple matches against an ambiguous prefix */
871 869 return -4;
872 870 }
873 871
874 872 static int nt_new(indexObject *self)
875 873 {
876 874 if (self->ntlength == self->ntcapacity) {
877 875 self->ntcapacity *= 2;
878 876 self->nt = realloc(self->nt,
879 877 self->ntcapacity * sizeof(nodetree));
880 878 if (self->nt == NULL) {
881 879 PyErr_SetString(PyExc_MemoryError, "out of memory");
882 880 return -1;
883 881 }
884 882 memset(&self->nt[self->ntlength], 0,
885 883 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
886 884 }
887 885 return self->ntlength++;
888 886 }
889 887
890 888 static int nt_insert(indexObject *self, const char *node, int rev)
891 889 {
892 890 int level = 0;
893 891 int off = 0;
894 892
895 893 while (level < 40) {
896 894 int k = nt_level(node, level);
897 895 nodetree *n;
898 896 int v;
899 897
900 898 n = &self->nt[off];
901 899 v = n->children[k];
902 900
903 901 if (v == 0) {
904 902 n->children[k] = -rev - 1;
905 903 return 0;
906 904 }
907 905 if (v < 0) {
908 906 const char *oldnode = index_node(self, -v - 1);
909 907 int noff;
910 908
911 909 if (!oldnode || !memcmp(oldnode, node, 20)) {
912 910 n->children[k] = -rev - 1;
913 911 return 0;
914 912 }
915 913 noff = nt_new(self);
916 914 if (noff == -1)
917 915 return -1;
918 916 /* self->nt may have been changed by realloc */
919 917 self->nt[off].children[k] = noff;
920 918 off = noff;
921 919 n = &self->nt[off];
922 920 n->children[nt_level(oldnode, ++level)] = v;
923 921 if (level > self->ntdepth)
924 922 self->ntdepth = level;
925 923 self->ntsplits += 1;
926 924 } else {
927 925 level += 1;
928 926 off = v;
929 927 }
930 928 }
931 929
932 930 return -1;
933 931 }
934 932
935 933 static int nt_init(indexObject *self)
936 934 {
937 935 if (self->nt == NULL) {
938 936 if (self->raw_length > INT_MAX) {
939 937 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
940 938 return -1;
941 939 }
942 940 self->ntcapacity = self->raw_length < 4
943 941 ? 4 : (int)self->raw_length / 2;
944 942
945 943 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
946 944 if (self->nt == NULL) {
947 945 PyErr_NoMemory();
948 946 return -1;
949 947 }
950 948 self->ntlength = 1;
951 949 self->ntrev = (int)index_length(self) - 1;
952 950 self->ntlookups = 1;
953 951 self->ntmisses = 0;
954 952 if (nt_insert(self, nullid, INT_MAX) == -1)
955 953 return -1;
956 954 }
957 955 return 0;
958 956 }
959 957
960 958 /*
961 959 * Return values:
962 960 *
963 961 * -3: error (exception set)
964 962 * -2: not found (no exception set)
965 963 * rest: valid rev
966 964 */
967 965 static int index_find_node(indexObject *self,
968 966 const char *node, Py_ssize_t nodelen)
969 967 {
970 968 int rev;
971 969
972 970 self->ntlookups++;
973 971 rev = nt_find(self, node, nodelen, 0);
974 972 if (rev >= -1)
975 973 return rev;
976 974
977 975 if (nt_init(self) == -1)
978 976 return -3;
979 977
980 978 /*
981 979 * For the first handful of lookups, we scan the entire index,
982 980 * and cache only the matching nodes. This optimizes for cases
983 981 * like "hg tip", where only a few nodes are accessed.
984 982 *
985 983 * After that, we cache every node we visit, using a single
986 984 * scan amortized over multiple lookups. This gives the best
987 985 * bulk performance, e.g. for "hg log".
988 986 */
989 987 if (self->ntmisses++ < 4) {
990 988 for (rev = self->ntrev - 1; rev >= 0; rev--) {
991 989 const char *n = index_node(self, rev);
992 990 if (n == NULL)
993 991 return -2;
994 992 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
995 993 if (nt_insert(self, n, rev) == -1)
996 994 return -3;
997 995 break;
998 996 }
999 997 }
1000 998 } else {
1001 999 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1002 1000 const char *n = index_node(self, rev);
1003 1001 if (n == NULL) {
1004 1002 self->ntrev = rev + 1;
1005 1003 return -2;
1006 1004 }
1007 1005 if (nt_insert(self, n, rev) == -1) {
1008 1006 self->ntrev = rev + 1;
1009 1007 return -3;
1010 1008 }
1011 1009 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1012 1010 break;
1013 1011 }
1014 1012 }
1015 1013 self->ntrev = rev;
1016 1014 }
1017 1015
1018 1016 if (rev >= 0)
1019 1017 return rev;
1020 1018 return -2;
1021 1019 }
1022 1020
1023 1021 static PyObject *raise_revlog_error(void)
1024 1022 {
1025 1023 static PyObject *errclass;
1026 1024 PyObject *mod = NULL, *errobj;
1027 1025
1028 1026 if (errclass == NULL) {
1029 1027 PyObject *dict;
1030 1028
1031 1029 mod = PyImport_ImportModule("mercurial.error");
1032 1030 if (mod == NULL)
1033 1031 goto classfail;
1034 1032
1035 1033 dict = PyModule_GetDict(mod);
1036 1034 if (dict == NULL)
1037 1035 goto classfail;
1038 1036
1039 1037 errclass = PyDict_GetItemString(dict, "RevlogError");
1040 1038 if (errclass == NULL) {
1041 1039 PyErr_SetString(PyExc_SystemError,
1042 1040 "could not find RevlogError");
1043 1041 goto classfail;
1044 1042 }
1045 1043 Py_INCREF(errclass);
1046 1044 }
1047 1045
1048 1046 errobj = PyObject_CallFunction(errclass, NULL);
1049 1047 if (errobj == NULL)
1050 1048 return NULL;
1051 1049 PyErr_SetObject(errclass, errobj);
1052 1050 return errobj;
1053 1051
1054 1052 classfail:
1055 1053 Py_XDECREF(mod);
1056 1054 return NULL;
1057 1055 }
1058 1056
1059 1057 static PyObject *index_getitem(indexObject *self, PyObject *value)
1060 1058 {
1061 1059 char *node;
1062 1060 Py_ssize_t nodelen;
1063 1061 int rev;
1064 1062
1065 1063 if (PyInt_Check(value))
1066 1064 return index_get(self, PyInt_AS_LONG(value));
1067 1065
1068 1066 if (node_check(value, &node, &nodelen) == -1)
1069 1067 return NULL;
1070 1068 rev = index_find_node(self, node, nodelen);
1071 1069 if (rev >= -1)
1072 1070 return PyInt_FromLong(rev);
1073 1071 if (rev == -2)
1074 1072 raise_revlog_error();
1075 1073 return NULL;
1076 1074 }
1077 1075
1078 1076 static int nt_partialmatch(indexObject *self, const char *node,
1079 1077 Py_ssize_t nodelen)
1080 1078 {
1081 1079 int rev;
1082 1080
1083 1081 if (nt_init(self) == -1)
1084 1082 return -3;
1085 1083
1086 1084 if (self->ntrev > 0) {
1087 1085 /* ensure that the radix tree is fully populated */
1088 1086 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1089 1087 const char *n = index_node(self, rev);
1090 1088 if (n == NULL)
1091 1089 return -2;
1092 1090 if (nt_insert(self, n, rev) == -1)
1093 1091 return -3;
1094 1092 }
1095 1093 self->ntrev = rev;
1096 1094 }
1097 1095
1098 1096 return nt_find(self, node, nodelen, 1);
1099 1097 }
1100 1098
1101 1099 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1102 1100 {
1103 1101 const char *fullnode;
1104 1102 int nodelen;
1105 1103 char *node;
1106 1104 int rev, i;
1107 1105
1108 1106 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1109 1107 return NULL;
1110 1108
1111 1109 if (nodelen < 4) {
1112 1110 PyErr_SetString(PyExc_ValueError, "key too short");
1113 1111 return NULL;
1114 1112 }
1115 1113
1116 1114 if (nodelen > 40) {
1117 1115 PyErr_SetString(PyExc_ValueError, "key too long");
1118 1116 return NULL;
1119 1117 }
1120 1118
1121 1119 for (i = 0; i < nodelen; i++)
1122 1120 hexdigit(node, i);
1123 1121 if (PyErr_Occurred()) {
1124 1122 /* input contains non-hex characters */
1125 1123 PyErr_Clear();
1126 1124 Py_RETURN_NONE;
1127 1125 }
1128 1126
1129 1127 rev = nt_partialmatch(self, node, nodelen);
1130 1128
1131 1129 switch (rev) {
1132 1130 case -4:
1133 1131 raise_revlog_error();
1134 1132 case -3:
1135 1133 return NULL;
1136 1134 case -2:
1137 1135 Py_RETURN_NONE;
1138 1136 case -1:
1139 1137 return PyString_FromStringAndSize(nullid, 20);
1140 1138 }
1141 1139
1142 1140 fullnode = index_node(self, rev);
1143 1141 if (fullnode == NULL) {
1144 1142 PyErr_Format(PyExc_IndexError,
1145 1143 "could not access rev %d", rev);
1146 1144 return NULL;
1147 1145 }
1148 1146 return PyString_FromStringAndSize(fullnode, 20);
1149 1147 }
1150 1148
1151 1149 static PyObject *index_m_get(indexObject *self, PyObject *args)
1152 1150 {
1153 1151 Py_ssize_t nodelen;
1154 1152 PyObject *val;
1155 1153 char *node;
1156 1154 int rev;
1157 1155
1158 1156 if (!PyArg_ParseTuple(args, "O", &val))
1159 1157 return NULL;
1160 1158 if (node_check(val, &node, &nodelen) == -1)
1161 1159 return NULL;
1162 1160 rev = index_find_node(self, node, nodelen);
1163 1161 if (rev == -3)
1164 1162 return NULL;
1165 1163 if (rev == -2)
1166 1164 Py_RETURN_NONE;
1167 1165 return PyInt_FromLong(rev);
1168 1166 }
1169 1167
1170 1168 static int index_contains(indexObject *self, PyObject *value)
1171 1169 {
1172 1170 char *node;
1173 1171 Py_ssize_t nodelen;
1174 1172
1175 1173 if (PyInt_Check(value)) {
1176 1174 long rev = PyInt_AS_LONG(value);
1177 1175 return rev >= -1 && rev < index_length(self);
1178 1176 }
1179 1177
1180 1178 if (node_check(value, &node, &nodelen) == -1)
1181 1179 return -1;
1182 1180
1183 1181 switch (index_find_node(self, node, nodelen)) {
1184 1182 case -3:
1185 1183 return -1;
1186 1184 case -2:
1187 1185 return 0;
1188 1186 default:
1189 1187 return 1;
1190 1188 }
1191 1189 }
1192 1190
1193 1191 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1194 1192 {
1195 1193 if (rev >= self->length - 1) {
1196 1194 PyObject *tuple = PyList_GET_ITEM(self->added,
1197 1195 rev - self->length + 1);
1198 1196 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1199 1197 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1200 1198 } else {
1201 1199 const char *data = index_deref(self, rev);
1202 1200 ps[0] = getbe32(data + 24);
1203 1201 ps[1] = getbe32(data + 28);
1204 1202 }
1205 1203 }
1206 1204
1207 1205 typedef uint64_t bitmask;
1208 1206
1209 1207 /*
1210 1208 * Given a disjoint set of revs, return all candidates for the
1211 1209 * greatest common ancestor. In revset notation, this is the set
1212 1210 * "heads(::a and ::b and ...)"
1213 1211 */
1214 1212 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1215 1213 int revcount)
1216 1214 {
1217 1215 const bitmask allseen = (1ull << revcount) - 1;
1218 1216 const bitmask poison = 1ull << revcount;
1219 1217 PyObject *gca = PyList_New(0);
1220 1218 int i, v, interesting;
1221 1219 int maxrev = -1;
1222 1220 long sp;
1223 1221 bitmask *seen;
1224 1222
1225 1223 if (gca == NULL)
1226 1224 return PyErr_NoMemory();
1227 1225
1228 1226 for (i = 0; i < revcount; i++) {
1229 1227 if (revs[i] > maxrev)
1230 1228 maxrev = revs[i];
1231 1229 }
1232 1230
1233 1231 seen = calloc(sizeof(*seen), maxrev + 1);
1234 1232 if (seen == NULL) {
1235 1233 Py_DECREF(gca);
1236 1234 return PyErr_NoMemory();
1237 1235 }
1238 1236
1239 1237 for (i = 0; i < revcount; i++)
1240 1238 seen[revs[i]] = 1ull << i;
1241 1239
1242 1240 interesting = revcount;
1243 1241
1244 1242 for (v = maxrev; v >= 0 && interesting; v--) {
1245 1243 long sv = seen[v];
1246 1244 int parents[2];
1247 1245
1248 1246 if (!sv)
1249 1247 continue;
1250 1248
1251 1249 if (sv < poison) {
1252 1250 interesting -= 1;
1253 1251 if (sv == allseen) {
1254 1252 PyObject *obj = PyInt_FromLong(v);
1255 1253 if (obj == NULL)
1256 1254 goto bail;
1257 1255 if (PyList_Append(gca, obj) == -1) {
1258 1256 Py_DECREF(obj);
1259 1257 goto bail;
1260 1258 }
1261 1259 sv |= poison;
1262 1260 for (i = 0; i < revcount; i++) {
1263 1261 if (revs[i] == v)
1264 1262 goto done;
1265 1263 }
1266 1264 }
1267 1265 }
1268 1266 index_get_parents(self, v, parents);
1269 1267
1270 1268 for (i = 0; i < 2; i++) {
1271 1269 int p = parents[i];
1272 1270 if (p == -1)
1273 1271 continue;
1274 1272 sp = seen[p];
1275 1273 if (sv < poison) {
1276 1274 if (sp == 0) {
1277 1275 seen[p] = sv;
1278 1276 interesting++;
1279 1277 }
1280 1278 else if (sp != sv)
1281 1279 seen[p] |= sv;
1282 1280 } else {
1283 1281 if (sp && sp < poison)
1284 1282 interesting--;
1285 1283 seen[p] = sv;
1286 1284 }
1287 1285 }
1288 1286 }
1289 1287
1290 1288 done:
1291 1289 free(seen);
1292 1290 return gca;
1293 1291 bail:
1294 1292 free(seen);
1295 1293 Py_XDECREF(gca);
1296 1294 return NULL;
1297 1295 }
1298 1296
1299 1297 /*
1300 1298 * Given a disjoint set of revs, return the subset with the longest
1301 1299 * path to the root.
1302 1300 */
1303 1301 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1304 1302 {
1305 1303 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1306 1304 static const Py_ssize_t capacity = 24;
1307 1305 int *depth, *interesting = NULL;
1308 1306 int i, j, v, ninteresting;
1309 1307 PyObject *dict = NULL, *keys = NULL;
1310 1308 long *seen = NULL;
1311 1309 int maxrev = -1;
1312 1310 long final;
1313 1311
1314 1312 if (revcount > capacity) {
1315 1313 PyErr_Format(PyExc_OverflowError,
1316 1314 "bitset size (%ld) > capacity (%ld)",
1317 1315 (long)revcount, (long)capacity);
1318 1316 return NULL;
1319 1317 }
1320 1318
1321 1319 for (i = 0; i < revcount; i++) {
1322 1320 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1323 1321 if (n > maxrev)
1324 1322 maxrev = n;
1325 1323 }
1326 1324
1327 1325 depth = calloc(sizeof(*depth), maxrev + 1);
1328 1326 if (depth == NULL)
1329 1327 return PyErr_NoMemory();
1330 1328
1331 1329 seen = calloc(sizeof(*seen), maxrev + 1);
1332 1330 if (seen == NULL) {
1333 1331 PyErr_NoMemory();
1334 1332 goto bail;
1335 1333 }
1336 1334
1337 1335 interesting = calloc(sizeof(*interesting), 2 << revcount);
1338 1336 if (interesting == NULL) {
1339 1337 PyErr_NoMemory();
1340 1338 goto bail;
1341 1339 }
1342 1340
1343 1341 if (PyList_Sort(revs) == -1)
1344 1342 goto bail;
1345 1343
1346 1344 for (i = 0; i < revcount; i++) {
1347 1345 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1348 1346 long b = 1l << i;
1349 1347 depth[n] = 1;
1350 1348 seen[n] = b;
1351 1349 interesting[b] = 1;
1352 1350 }
1353 1351
1354 1352 ninteresting = (int)revcount;
1355 1353
1356 1354 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1357 1355 int dv = depth[v];
1358 1356 int parents[2];
1359 1357 long sv;
1360 1358
1361 1359 if (dv == 0)
1362 1360 continue;
1363 1361
1364 1362 sv = seen[v];
1365 1363 index_get_parents(self, v, parents);
1366 1364
1367 1365 for (i = 0; i < 2; i++) {
1368 1366 int p = parents[i];
1369 1367 long nsp, sp;
1370 1368 int dp;
1371 1369
1372 1370 if (p == -1)
1373 1371 continue;
1374 1372
1375 1373 dp = depth[p];
1376 1374 nsp = sp = seen[p];
1377 1375 if (dp <= dv) {
1378 1376 depth[p] = dv + 1;
1379 1377 if (sp != sv) {
1380 1378 interesting[sv] += 1;
1381 1379 nsp = seen[p] = sv;
1382 1380 if (sp) {
1383 1381 interesting[sp] -= 1;
1384 1382 if (interesting[sp] == 0)
1385 1383 ninteresting -= 1;
1386 1384 }
1387 1385 }
1388 1386 }
1389 1387 else if (dv == dp - 1) {
1390 1388 nsp = sp | sv;
1391 1389 if (nsp == sp)
1392 1390 continue;
1393 1391 seen[p] = nsp;
1394 1392 interesting[sp] -= 1;
1395 1393 if (interesting[sp] == 0 && interesting[nsp] > 0)
1396 1394 ninteresting -= 1;
1397 1395 interesting[nsp] += 1;
1398 1396 }
1399 1397 }
1400 1398 interesting[sv] -= 1;
1401 1399 if (interesting[sv] == 0)
1402 1400 ninteresting -= 1;
1403 1401 }
1404 1402
1405 1403 final = 0;
1406 1404 j = ninteresting;
1407 1405 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1408 1406 if (interesting[i] == 0)
1409 1407 continue;
1410 1408 final |= i;
1411 1409 j -= 1;
1412 1410 }
1413 1411 if (final == 0) {
1414 1412 keys = PyList_New(0);
1415 1413 goto bail;
1416 1414 }
1417 1415
1418 1416 dict = PyDict_New();
1419 1417 if (dict == NULL)
1420 1418 goto bail;
1421 1419
1422 1420 for (i = 0; i < revcount; i++) {
1423 1421 PyObject *key;
1424 1422
1425 1423 if ((final & (1 << i)) == 0)
1426 1424 continue;
1427 1425
1428 1426 key = PyList_GET_ITEM(revs, i);
1429 1427 Py_INCREF(key);
1430 1428 Py_INCREF(Py_None);
1431 1429 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1432 1430 Py_DECREF(key);
1433 1431 Py_DECREF(Py_None);
1434 1432 goto bail;
1435 1433 }
1436 1434 }
1437 1435
1438 1436 keys = PyDict_Keys(dict);
1439 1437
1440 1438 bail:
1441 1439 free(depth);
1442 1440 free(seen);
1443 1441 free(interesting);
1444 1442 Py_XDECREF(dict);
1445 1443
1446 1444 return keys;
1447 1445 }
1448 1446
1449 1447 /*
1450 1448 * Given a (possibly overlapping) set of revs, return the greatest
1451 1449 * common ancestors: those with the longest path to the root.
1452 1450 */
1453 1451 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1454 1452 {
1455 1453 PyObject *ret = NULL, *gca = NULL;
1456 1454 Py_ssize_t argcount, i, len;
1457 1455 bitmask repeat = 0;
1458 1456 int revcount = 0;
1459 1457 int *revs;
1460 1458
1461 1459 argcount = PySequence_Length(args);
1462 1460 revs = malloc(argcount * sizeof(*revs));
1463 1461 if (argcount > 0 && revs == NULL)
1464 1462 return PyErr_NoMemory();
1465 1463 len = index_length(self) - 1;
1466 1464
1467 1465 for (i = 0; i < argcount; i++) {
1468 1466 static const int capacity = 24;
1469 1467 PyObject *obj = PySequence_GetItem(args, i);
1470 1468 bitmask x;
1471 1469 long val;
1472 1470
1473 1471 if (!PyInt_Check(obj)) {
1474 1472 PyErr_SetString(PyExc_TypeError,
1475 1473 "arguments must all be ints");
1476 1474 goto bail;
1477 1475 }
1478 1476 val = PyInt_AsLong(obj);
1479 1477 if (val == -1) {
1480 1478 ret = PyList_New(0);
1481 1479 goto done;
1482 1480 }
1483 1481 if (val < 0 || val >= len) {
1484 1482 PyErr_SetString(PyExc_IndexError,
1485 1483 "index out of range");
1486 1484 goto bail;
1487 1485 }
1488 1486 /* this cheesy bloom filter lets us avoid some more
1489 1487 * expensive duplicate checks in the common set-is-disjoint
1490 1488 * case */
1491 1489 x = 1ull << (val & 0x3f);
1492 1490 if (repeat & x) {
1493 1491 int k;
1494 1492 for (k = 0; k < revcount; k++) {
1495 1493 if (val == revs[k])
1496 1494 goto duplicate;
1497 1495 }
1498 1496 }
1499 1497 else repeat |= x;
1500 1498 if (revcount >= capacity) {
1501 1499 PyErr_Format(PyExc_OverflowError,
1502 1500 "bitset size (%d) > capacity (%d)",
1503 1501 revcount, capacity);
1504 1502 goto bail;
1505 1503 }
1506 1504 revs[revcount++] = (int)val;
1507 1505 duplicate:;
1508 1506 }
1509 1507
1510 1508 if (revcount == 0) {
1511 1509 ret = PyList_New(0);
1512 1510 goto done;
1513 1511 }
1514 1512 if (revcount == 1) {
1515 1513 PyObject *obj;
1516 1514 ret = PyList_New(1);
1517 1515 if (ret == NULL)
1518 1516 goto bail;
1519 1517 obj = PyInt_FromLong(revs[0]);
1520 1518 if (obj == NULL)
1521 1519 goto bail;
1522 1520 PyList_SET_ITEM(ret, 0, obj);
1523 1521 goto done;
1524 1522 }
1525 1523
1526 1524 gca = find_gca_candidates(self, revs, revcount);
1527 1525 if (gca == NULL)
1528 1526 goto bail;
1529 1527
1530 1528 if (PyList_GET_SIZE(gca) <= 1) {
1531 1529 ret = gca;
1532 1530 Py_INCREF(gca);
1533 1531 }
1534 1532 else ret = find_deepest(self, gca);
1535 1533
1536 1534 done:
1537 1535 free(revs);
1538 1536 Py_XDECREF(gca);
1539 1537
1540 1538 return ret;
1541 1539
1542 1540 bail:
1543 1541 free(revs);
1544 1542 Py_XDECREF(gca);
1545 1543 Py_XDECREF(ret);
1546 1544 return NULL;
1547 1545 }
1548 1546
1549 1547 /*
1550 1548 * Given a (possibly overlapping) set of revs, return all the
1551 1549 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1552 1550 */
1553 1551 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1554 1552 {
1555 1553 PyObject *ret = NULL;
1556 1554 Py_ssize_t argcount, i, len;
1557 1555 bitmask repeat = 0;
1558 1556 int revcount = 0;
1559 1557 int *revs;
1560 1558
1561 1559 argcount = PySequence_Length(args);
1562 1560 revs = malloc(argcount * sizeof(*revs));
1563 1561 if (argcount > 0 && revs == NULL)
1564 1562 return PyErr_NoMemory();
1565 1563 len = index_length(self) - 1;
1566 1564
1567 1565 for (i = 0; i < argcount; i++) {
1568 1566 static const int capacity = 24;
1569 1567 PyObject *obj = PySequence_GetItem(args, i);
1570 1568 bitmask x;
1571 1569 long val;
1572 1570
1573 1571 if (!PyInt_Check(obj)) {
1574 1572 PyErr_SetString(PyExc_TypeError,
1575 1573 "arguments must all be ints");
1576 1574 goto bail;
1577 1575 }
1578 1576 val = PyInt_AsLong(obj);
1579 1577 if (val == -1) {
1580 1578 ret = PyList_New(0);
1581 1579 goto done;
1582 1580 }
1583 1581 if (val < 0 || val >= len) {
1584 1582 PyErr_SetString(PyExc_IndexError,
1585 1583 "index out of range");
1586 1584 goto bail;
1587 1585 }
1588 1586 /* this cheesy bloom filter lets us avoid some more
1589 1587 * expensive duplicate checks in the common set-is-disjoint
1590 1588 * case */
1591 1589 x = 1ull << (val & 0x3f);
1592 1590 if (repeat & x) {
1593 1591 int k;
1594 1592 for (k = 0; k < revcount; k++) {
1595 1593 if (val == revs[k])
1596 1594 goto duplicate;
1597 1595 }
1598 1596 }
1599 1597 else repeat |= x;
1600 1598 if (revcount >= capacity) {
1601 1599 PyErr_Format(PyExc_OverflowError,
1602 1600 "bitset size (%d) > capacity (%d)",
1603 1601 revcount, capacity);
1604 1602 goto bail;
1605 1603 }
1606 1604 revs[revcount++] = (int)val;
1607 1605 duplicate:;
1608 1606 }
1609 1607
1610 1608 if (revcount == 0) {
1611 1609 ret = PyList_New(0);
1612 1610 goto done;
1613 1611 }
1614 1612 if (revcount == 1) {
1615 1613 PyObject *obj;
1616 1614 ret = PyList_New(1);
1617 1615 if (ret == NULL)
1618 1616 goto bail;
1619 1617 obj = PyInt_FromLong(revs[0]);
1620 1618 if (obj == NULL)
1621 1619 goto bail;
1622 1620 PyList_SET_ITEM(ret, 0, obj);
1623 1621 goto done;
1624 1622 }
1625 1623
1626 1624 ret = find_gca_candidates(self, revs, revcount);
1627 1625 if (ret == NULL)
1628 1626 goto bail;
1629 1627
1630 1628 done:
1631 1629 free(revs);
1632 1630 return ret;
1633 1631
1634 1632 bail:
1635 1633 free(revs);
1636 1634 Py_XDECREF(ret);
1637 1635 return NULL;
1638 1636 }
1639 1637
1640 1638 /*
1641 1639 * Invalidate any trie entries introduced by added revs.
1642 1640 */
1643 1641 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1644 1642 {
1645 1643 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1646 1644
1647 1645 for (i = start; i < len; i++) {
1648 1646 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1649 1647 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1650 1648
1651 1649 nt_insert(self, PyString_AS_STRING(node), -1);
1652 1650 }
1653 1651
1654 1652 if (start == 0)
1655 1653 Py_CLEAR(self->added);
1656 1654 }
1657 1655
1658 1656 /*
1659 1657 * Delete a numeric range of revs, which must be at the end of the
1660 1658 * range, but exclude the sentinel nullid entry.
1661 1659 */
1662 1660 static int index_slice_del(indexObject *self, PyObject *item)
1663 1661 {
1664 1662 Py_ssize_t start, stop, step, slicelength;
1665 1663 Py_ssize_t length = index_length(self);
1666 1664 int ret = 0;
1667 1665
1668 1666 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1669 1667 &start, &stop, &step, &slicelength) < 0)
1670 1668 return -1;
1671 1669
1672 1670 if (slicelength <= 0)
1673 1671 return 0;
1674 1672
1675 1673 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1676 1674 stop = start;
1677 1675
1678 1676 if (step < 0) {
1679 1677 stop = start + 1;
1680 1678 start = stop + step*(slicelength - 1) - 1;
1681 1679 step = -step;
1682 1680 }
1683 1681
1684 1682 if (step != 1) {
1685 1683 PyErr_SetString(PyExc_ValueError,
1686 1684 "revlog index delete requires step size of 1");
1687 1685 return -1;
1688 1686 }
1689 1687
1690 1688 if (stop != length - 1) {
1691 1689 PyErr_SetString(PyExc_IndexError,
1692 1690 "revlog index deletion indices are invalid");
1693 1691 return -1;
1694 1692 }
1695 1693
1696 1694 if (start < self->length - 1) {
1697 1695 if (self->nt) {
1698 1696 Py_ssize_t i;
1699 1697
1700 1698 for (i = start + 1; i < self->length - 1; i++) {
1701 1699 const char *node = index_node(self, i);
1702 1700
1703 1701 if (node)
1704 1702 nt_insert(self, node, -1);
1705 1703 }
1706 1704 if (self->added)
1707 1705 nt_invalidate_added(self, 0);
1708 1706 if (self->ntrev > start)
1709 1707 self->ntrev = (int)start;
1710 1708 }
1711 1709 self->length = start + 1;
1712 1710 if (start < self->raw_length) {
1713 1711 if (self->cache) {
1714 1712 Py_ssize_t i;
1715 1713 for (i = start; i < self->raw_length; i++)
1716 1714 Py_CLEAR(self->cache[i]);
1717 1715 }
1718 1716 self->raw_length = start;
1719 1717 }
1720 1718 goto done;
1721 1719 }
1722 1720
1723 1721 if (self->nt) {
1724 1722 nt_invalidate_added(self, start - self->length + 1);
1725 1723 if (self->ntrev > start)
1726 1724 self->ntrev = (int)start;
1727 1725 }
1728 1726 if (self->added)
1729 1727 ret = PyList_SetSlice(self->added, start - self->length + 1,
1730 1728 PyList_GET_SIZE(self->added), NULL);
1731 1729 done:
1732 1730 Py_CLEAR(self->headrevs);
1733 1731 return ret;
1734 1732 }
1735 1733
1736 1734 /*
1737 1735 * Supported ops:
1738 1736 *
1739 1737 * slice deletion
1740 1738 * string assignment (extend node->rev mapping)
1741 1739 * string deletion (shrink node->rev mapping)
1742 1740 */
1743 1741 static int index_assign_subscript(indexObject *self, PyObject *item,
1744 1742 PyObject *value)
1745 1743 {
1746 1744 char *node;
1747 1745 Py_ssize_t nodelen;
1748 1746 long rev;
1749 1747
1750 1748 if (PySlice_Check(item) && value == NULL)
1751 1749 return index_slice_del(self, item);
1752 1750
1753 1751 if (node_check(item, &node, &nodelen) == -1)
1754 1752 return -1;
1755 1753
1756 1754 if (value == NULL)
1757 1755 return self->nt ? nt_insert(self, node, -1) : 0;
1758 1756 rev = PyInt_AsLong(value);
1759 1757 if (rev > INT_MAX || rev < 0) {
1760 1758 if (!PyErr_Occurred())
1761 1759 PyErr_SetString(PyExc_ValueError, "rev out of range");
1762 1760 return -1;
1763 1761 }
1764 1762 return nt_insert(self, node, (int)rev);
1765 1763 }
1766 1764
1767 1765 /*
1768 1766 * Find all RevlogNG entries in an index that has inline data. Update
1769 1767 * the optional "offsets" table with those entries.
1770 1768 */
1771 1769 static long inline_scan(indexObject *self, const char **offsets)
1772 1770 {
1773 1771 const char *data = PyString_AS_STRING(self->data);
1774 1772 Py_ssize_t pos = 0;
1775 1773 Py_ssize_t end = PyString_GET_SIZE(self->data);
1776 1774 long incr = v1_hdrsize;
1777 1775 Py_ssize_t len = 0;
1778 1776
1779 1777 while (pos + v1_hdrsize <= end && pos >= 0) {
1780 1778 uint32_t comp_len;
1781 1779 /* 3rd element of header is length of compressed inline data */
1782 1780 comp_len = getbe32(data + pos + 8);
1783 1781 incr = v1_hdrsize + comp_len;
1784 1782 if (offsets)
1785 1783 offsets[len] = data + pos;
1786 1784 len++;
1787 1785 pos += incr;
1788 1786 }
1789 1787
1790 1788 if (pos != end) {
1791 1789 if (!PyErr_Occurred())
1792 1790 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1793 1791 return -1;
1794 1792 }
1795 1793
1796 1794 return len;
1797 1795 }
1798 1796
1799 1797 static int index_init(indexObject *self, PyObject *args)
1800 1798 {
1801 1799 PyObject *data_obj, *inlined_obj;
1802 1800 Py_ssize_t size;
1803 1801
1804 1802 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1805 1803 self->raw_length = 0;
1806 1804 self->added = NULL;
1807 1805 self->cache = NULL;
1808 1806 self->data = NULL;
1809 1807 self->headrevs = NULL;
1810 1808 self->nt = NULL;
1811 1809 self->offsets = NULL;
1812 1810
1813 1811 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1814 1812 return -1;
1815 1813 if (!PyString_Check(data_obj)) {
1816 1814 PyErr_SetString(PyExc_TypeError, "data is not a string");
1817 1815 return -1;
1818 1816 }
1819 1817 size = PyString_GET_SIZE(data_obj);
1820 1818
1821 1819 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1822 1820 self->data = data_obj;
1823 1821
1824 1822 self->ntlength = self->ntcapacity = 0;
1825 1823 self->ntdepth = self->ntsplits = 0;
1826 1824 self->ntlookups = self->ntmisses = 0;
1827 1825 self->ntrev = -1;
1828 1826 Py_INCREF(self->data);
1829 1827
1830 1828 if (self->inlined) {
1831 1829 long len = inline_scan(self, NULL);
1832 1830 if (len == -1)
1833 1831 goto bail;
1834 1832 self->raw_length = len;
1835 1833 self->length = len + 1;
1836 1834 } else {
1837 1835 if (size % v1_hdrsize) {
1838 1836 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1839 1837 goto bail;
1840 1838 }
1841 1839 self->raw_length = size / v1_hdrsize;
1842 1840 self->length = self->raw_length + 1;
1843 1841 }
1844 1842
1845 1843 return 0;
1846 1844 bail:
1847 1845 return -1;
1848 1846 }
1849 1847
1850 1848 static PyObject *index_nodemap(indexObject *self)
1851 1849 {
1852 1850 Py_INCREF(self);
1853 1851 return (PyObject *)self;
1854 1852 }
1855 1853
1856 1854 static void index_dealloc(indexObject *self)
1857 1855 {
1858 1856 _index_clearcaches(self);
1859 1857 Py_XDECREF(self->data);
1860 1858 Py_XDECREF(self->added);
1861 1859 PyObject_Del(self);
1862 1860 }
1863 1861
1864 1862 static PySequenceMethods index_sequence_methods = {
1865 1863 (lenfunc)index_length, /* sq_length */
1866 1864 0, /* sq_concat */
1867 1865 0, /* sq_repeat */
1868 1866 (ssizeargfunc)index_get, /* sq_item */
1869 1867 0, /* sq_slice */
1870 1868 0, /* sq_ass_item */
1871 1869 0, /* sq_ass_slice */
1872 1870 (objobjproc)index_contains, /* sq_contains */
1873 1871 };
1874 1872
1875 1873 static PyMappingMethods index_mapping_methods = {
1876 1874 (lenfunc)index_length, /* mp_length */
1877 1875 (binaryfunc)index_getitem, /* mp_subscript */
1878 1876 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1879 1877 };
1880 1878
1881 1879 static PyMethodDef index_methods[] = {
1882 1880 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1883 1881 "return the gca set of the given revs"},
1884 1882 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1885 1883 METH_VARARGS,
1886 1884 "return the heads of the common ancestors of the given revs"},
1887 1885 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1888 1886 "clear the index caches"},
1889 1887 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1890 1888 "get an index entry"},
1891 1889 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1892 1890 "get head revisions"},
1893 1891 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1894 1892 "insert an index entry"},
1895 1893 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1896 1894 "match a potentially ambiguous node ID"},
1897 1895 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1898 1896 "stats for the index"},
1899 1897 {NULL} /* Sentinel */
1900 1898 };
1901 1899
1902 1900 static PyGetSetDef index_getset[] = {
1903 1901 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1904 1902 {NULL} /* Sentinel */
1905 1903 };
1906 1904
1907 1905 static PyTypeObject indexType = {
1908 1906 PyObject_HEAD_INIT(NULL)
1909 1907 0, /* ob_size */
1910 1908 "parsers.index", /* tp_name */
1911 1909 sizeof(indexObject), /* tp_basicsize */
1912 1910 0, /* tp_itemsize */
1913 1911 (destructor)index_dealloc, /* tp_dealloc */
1914 1912 0, /* tp_print */
1915 1913 0, /* tp_getattr */
1916 1914 0, /* tp_setattr */
1917 1915 0, /* tp_compare */
1918 1916 0, /* tp_repr */
1919 1917 0, /* tp_as_number */
1920 1918 &index_sequence_methods, /* tp_as_sequence */
1921 1919 &index_mapping_methods, /* tp_as_mapping */
1922 1920 0, /* tp_hash */
1923 1921 0, /* tp_call */
1924 1922 0, /* tp_str */
1925 1923 0, /* tp_getattro */
1926 1924 0, /* tp_setattro */
1927 1925 0, /* tp_as_buffer */
1928 1926 Py_TPFLAGS_DEFAULT, /* tp_flags */
1929 1927 "revlog index", /* tp_doc */
1930 1928 0, /* tp_traverse */
1931 1929 0, /* tp_clear */
1932 1930 0, /* tp_richcompare */
1933 1931 0, /* tp_weaklistoffset */
1934 1932 0, /* tp_iter */
1935 1933 0, /* tp_iternext */
1936 1934 index_methods, /* tp_methods */
1937 1935 0, /* tp_members */
1938 1936 index_getset, /* tp_getset */
1939 1937 0, /* tp_base */
1940 1938 0, /* tp_dict */
1941 1939 0, /* tp_descr_get */
1942 1940 0, /* tp_descr_set */
1943 1941 0, /* tp_dictoffset */
1944 1942 (initproc)index_init, /* tp_init */
1945 1943 0, /* tp_alloc */
1946 1944 };
1947 1945
1948 1946 /*
1949 1947 * returns a tuple of the form (index, index, cache) with elements as
1950 1948 * follows:
1951 1949 *
1952 1950 * index: an index object that lazily parses RevlogNG records
1953 1951 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1954 1952 *
1955 1953 * added complications are for backwards compatibility
1956 1954 */
1957 1955 static PyObject *parse_index2(PyObject *self, PyObject *args)
1958 1956 {
1959 1957 PyObject *tuple = NULL, *cache = NULL;
1960 1958 indexObject *idx;
1961 1959 int ret;
1962 1960
1963 1961 idx = PyObject_New(indexObject, &indexType);
1964 1962 if (idx == NULL)
1965 1963 goto bail;
1966 1964
1967 1965 ret = index_init(idx, args);
1968 1966 if (ret == -1)
1969 1967 goto bail;
1970 1968
1971 1969 if (idx->inlined) {
1972 1970 cache = Py_BuildValue("iO", 0, idx->data);
1973 1971 if (cache == NULL)
1974 1972 goto bail;
1975 1973 } else {
1976 1974 cache = Py_None;
1977 1975 Py_INCREF(cache);
1978 1976 }
1979 1977
1980 1978 tuple = Py_BuildValue("NN", idx, cache);
1981 1979 if (!tuple)
1982 1980 goto bail;
1983 1981 return tuple;
1984 1982
1985 1983 bail:
1986 1984 Py_XDECREF(idx);
1987 1985 Py_XDECREF(cache);
1988 1986 Py_XDECREF(tuple);
1989 1987 return NULL;
1990 1988 }
1991 1989
1992 1990 static char parsers_doc[] = "Efficient content parsing.";
1993 1991
1994 1992 PyObject *encodedir(PyObject *self, PyObject *args);
1995 1993 PyObject *pathencode(PyObject *self, PyObject *args);
1996 1994 PyObject *lowerencode(PyObject *self, PyObject *args);
1997 1995
1998 1996 static PyMethodDef methods[] = {
1999 1997 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2000 1998 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2001 1999 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2002 2000 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2003 2001 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2004 2002 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2005 2003 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2006 2004 {NULL, NULL}
2007 2005 };
2008 2006
2009 2007 void dirs_module_init(PyObject *mod);
2010 2008
2011 2009 static void module_init(PyObject *mod)
2012 2010 {
2013 2011 /* This module constant has two purposes. First, it lets us unit test
2014 2012 * the ImportError raised without hard-coding any error text. This
2015 2013 * means we can change the text in the future without breaking tests,
2016 2014 * even across changesets without a recompile. Second, its presence
2017 2015 * can be used to determine whether the version-checking logic is
2018 2016 * present, which also helps in testing across changesets without a
2019 2017 * recompile. Note that this means the pure-Python version of parsers
2020 2018 * should not have this module constant. */
2021 2019 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2022 2020
2023 2021 dirs_module_init(mod);
2024 2022
2025 2023 indexType.tp_new = PyType_GenericNew;
2026 2024 if (PyType_Ready(&indexType) < 0)
2027 2025 return;
2028 2026 Py_INCREF(&indexType);
2029 2027
2030 2028 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2031 2029
2032 2030 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2033 2031 -1, -1, -1, -1, nullid, 20);
2034 2032 if (nullentry)
2035 2033 PyObject_GC_UnTrack(nullentry);
2036
2037 dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1);
2038 2034 }
2039 2035
2040 2036 static int check_python_version(void)
2041 2037 {
2042 2038 PyObject *sys = PyImport_ImportModule("sys");
2043 2039 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2044 2040 /* sys.hexversion is a 32-bit number by default, so the -1 case
2045 2041 * should only occur in unusual circumstances (e.g. if sys.hexversion
2046 2042 * is manually set to an invalid value). */
2047 2043 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2048 2044 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2049 2045 "modules were compiled with Python " PY_VERSION ", but "
2050 2046 "Mercurial is currently using Python with sys.hexversion=%ld: "
2051 2047 "Python %s\n at: %s", versionerrortext, hexversion,
2052 2048 Py_GetVersion(), Py_GetProgramFullPath());
2053 2049 return -1;
2054 2050 }
2055 2051 return 0;
2056 2052 }
2057 2053
2058 2054 #ifdef IS_PY3K
2059 2055 static struct PyModuleDef parsers_module = {
2060 2056 PyModuleDef_HEAD_INIT,
2061 2057 "parsers",
2062 2058 parsers_doc,
2063 2059 -1,
2064 2060 methods
2065 2061 };
2066 2062
2067 2063 PyMODINIT_FUNC PyInit_parsers(void)
2068 2064 {
2069 2065 PyObject *mod;
2070 2066
2071 2067 if (check_python_version() == -1)
2072 2068 return;
2073 2069 mod = PyModule_Create(&parsers_module);
2074 2070 module_init(mod);
2075 2071 return mod;
2076 2072 }
2077 2073 #else
2078 2074 PyMODINIT_FUNC initparsers(void)
2079 2075 {
2080 2076 PyObject *mod;
2081 2077
2082 2078 if (check_python_version() == -1)
2083 2079 return;
2084 2080 mod = Py_InitModule3("parsers", methods, parsers_doc);
2085 2081 module_init(mod);
2086 2082 }
2087 2083 #endif
General Comments 0
You need to be logged in to leave comments. Login now