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