comparison mercurial/parsers.c @ 16786:2631cd5dd244

revlog: switch to a C version of headrevs The C implementation is more than 100 times faster than the Python version (which is still available as a fallback). In a repo with 330,000 revs and a stale .hg/cache/tags file, this patch improves the performance of "hg tip" from 2.2 to 1.6 seconds.
author Bryan O'Sullivan <bryano@fb.com>
date Sat, 19 May 2012 19:44:58 -0700
parents 12a852c7c763
children bda96ce993f9
comparison
equal deleted inserted replaced
16785:1dc08dc63c09 16786:2631cd5dd244
532 bail: 532 bail:
533 Py_XDECREF(obj); 533 Py_XDECREF(obj);
534 return NULL; 534 return NULL;
535 } 535 }
536 536
537 static PyObject *index_headrevs(indexObject *self)
538 {
539 Py_ssize_t i, len, addlen;
540 char *nothead = NULL;
541 PyObject *heads;
542
543 len = index_length(self) - 1;
544 heads = PyList_New(0);
545 if (heads == NULL)
546 goto bail;
547 if (len == 0) {
548 PyObject *nullid = PyInt_FromLong(-1);
549 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
550 Py_XDECREF(nullid);
551 goto bail;
552 }
553 goto done;
554 }
555
556 nothead = calloc(len, 1);
557 if (nothead == NULL)
558 goto bail;
559
560 for (i = 0; i < self->raw_length; i++) {
561 const char *data = index_deref(self, i);
562 int parent_1 = getbe32(data + 24);
563 int parent_2 = getbe32(data + 28);
564 if (parent_1 >= 0)
565 nothead[parent_1] = 1;
566 if (parent_2 >= 0)
567 nothead[parent_2] = 1;
568 }
569
570 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
571
572 for (i = 0; i < addlen; i++) {
573 PyObject *rev = PyList_GET_ITEM(self->added, i);
574 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
575 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
576 long parent_1, parent_2;
577
578 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
579 PyErr_SetString(PyExc_TypeError,
580 "revlog parents are invalid");
581 goto bail;
582 }
583 parent_1 = PyInt_AS_LONG(p1);
584 parent_2 = PyInt_AS_LONG(p2);
585 if (parent_1 >= 0)
586 nothead[parent_1] = 1;
587 if (parent_2 >= 0)
588 nothead[parent_2] = 1;
589 }
590
591 for (i = 0; i < len; i++) {
592 PyObject *head;
593
594 if (nothead[i])
595 continue;
596 head = PyInt_FromLong(i);
597 if (head == NULL || PyList_Append(heads, head) == -1) {
598 Py_XDECREF(head);
599 goto bail;
600 }
601 }
602
603 done:
604 free(nothead);
605 return heads;
606 bail:
607 Py_XDECREF(heads);
608 free(nothead);
609 return NULL;
610 }
611
537 static inline int nt_level(const char *node, Py_ssize_t level) 612 static inline int nt_level(const char *node, Py_ssize_t level)
538 { 613 {
539 int v = node[level>>1]; 614 int v = node[level>>1];
540 if (!(level & 1)) 615 if (!(level & 1))
541 v >>= 4; 616 v >>= 4;
1142 static PyMethodDef index_methods[] = { 1217 static PyMethodDef index_methods[] = {
1143 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS, 1218 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1144 "clear the index caches"}, 1219 "clear the index caches"},
1145 {"get", (PyCFunction)index_m_get, METH_VARARGS, 1220 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1146 "get an index entry"}, 1221 "get an index entry"},
1222 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1223 "get head revisions"},
1147 {"insert", (PyCFunction)index_insert, METH_VARARGS, 1224 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1148 "insert an index entry"}, 1225 "insert an index entry"},
1149 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS, 1226 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1150 "match a potentially ambiguous node ID"}, 1227 "match a potentially ambiguous node ID"},
1151 {"stats", (PyCFunction)index_stats, METH_NOARGS, 1228 {"stats", (PyCFunction)index_stats, METH_NOARGS,