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