40 * Positive value is index of the next node in the trie |
40 * Positive value is index of the next node in the trie |
41 * Negative value is a leaf: -(rev + 2) |
41 * Negative value is a leaf: -(rev + 2) |
42 * Zero is empty |
42 * Zero is empty |
43 */ |
43 */ |
44 typedef struct { |
44 typedef struct { |
45 PyObject_HEAD |
|
46 indexObject *index; |
45 indexObject *index; |
47 nodetreenode *nodes; |
46 nodetreenode *nodes; |
48 unsigned length; /* # nodes in use */ |
47 unsigned length; /* # nodes in use */ |
49 unsigned capacity; /* # nodes allocated */ |
48 unsigned capacity; /* # nodes allocated */ |
50 int depth; /* maximum depth of tree */ |
49 int depth; /* maximum depth of tree */ |
51 int splits; /* # splits performed */ |
50 int splits; /* # splits performed */ |
52 } nodetree; |
51 } nodetree; |
|
52 |
|
53 typedef struct { |
|
54 PyObject_HEAD |
|
55 nodetree nt; |
|
56 } nodetreeObject; |
53 |
57 |
54 /* |
58 /* |
55 * This class has two behaviors. |
59 * This class has two behaviors. |
56 * |
60 * |
57 * When used in a list-like way (with integer keys), we decode an |
61 * When used in a list-like way (with integer keys), we decode an |
73 Py_ssize_t raw_length; /* original number of elements */ |
77 Py_ssize_t raw_length; /* original number of elements */ |
74 Py_ssize_t length; /* current number of elements */ |
78 Py_ssize_t length; /* current number of elements */ |
75 PyObject *added; /* populated on demand */ |
79 PyObject *added; /* populated on demand */ |
76 PyObject *headrevs; /* cache, invalidated on changes */ |
80 PyObject *headrevs; /* cache, invalidated on changes */ |
77 PyObject *filteredrevs;/* filtered revs set */ |
81 PyObject *filteredrevs;/* filtered revs set */ |
78 nodetree *nt; /* base-16 trie */ |
82 nodetree nt; /* base-16 trie */ |
|
83 int ntinitialized; /* 0 or 1 */ |
79 int ntrev; /* last rev scanned */ |
84 int ntrev; /* last rev scanned */ |
80 int ntlookups; /* # lookups */ |
85 int ntlookups; /* # lookups */ |
81 int ntmisses; /* # lookups that miss the cache */ |
86 int ntmisses; /* # lookups that miss the cache */ |
82 int inlined; |
87 int inlined; |
83 }; |
88 }; |
372 istat(raw_length, "revs on disk"); |
377 istat(raw_length, "revs on disk"); |
373 istat(length, "revs in memory"); |
378 istat(length, "revs in memory"); |
374 istat(ntlookups, "node trie lookups"); |
379 istat(ntlookups, "node trie lookups"); |
375 istat(ntmisses, "node trie misses"); |
380 istat(ntmisses, "node trie misses"); |
376 istat(ntrev, "node trie last rev scanned"); |
381 istat(ntrev, "node trie last rev scanned"); |
377 if (self->nt) { |
382 if (self->ntinitialized) { |
378 istat(nt->capacity, "node trie capacity"); |
383 istat(nt.capacity, "node trie capacity"); |
379 istat(nt->depth, "node trie depth"); |
384 istat(nt.depth, "node trie depth"); |
380 istat(nt->length, "node trie count"); |
385 istat(nt.length, "node trie count"); |
381 istat(nt->splits, "node trie splits"); |
386 istat(nt.splits, "node trie splits"); |
382 } |
387 } |
383 |
388 |
384 #undef istat |
389 #undef istat |
385 |
390 |
386 return obj; |
391 return obj; |
1085 } |
1090 } |
1086 |
1091 |
1087 return -1; |
1092 return -1; |
1088 } |
1093 } |
1089 |
1094 |
1090 static PyObject *nt_insert_py(nodetree *self, PyObject *args) |
1095 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args) |
1091 { |
1096 { |
1092 Py_ssize_t rev; |
1097 Py_ssize_t rev; |
1093 const char *node; |
1098 const char *node; |
1094 Py_ssize_t length; |
1099 Py_ssize_t length; |
1095 if (!PyArg_ParseTuple(args, "n", &rev)) |
1100 if (!PyArg_ParseTuple(args, "n", &rev)) |
1096 return NULL; |
1101 return NULL; |
1097 length = index_length(self->index); |
1102 length = index_length(self->nt.index); |
1098 if (rev < 0 || rev >= length) { |
1103 if (rev < 0 || rev >= length) { |
1099 PyErr_SetString(PyExc_ValueError, "revlog index out of range"); |
1104 PyErr_SetString(PyExc_ValueError, "revlog index out of range"); |
1100 return NULL; |
1105 return NULL; |
1101 } |
1106 } |
1102 node = index_node_existing(self->index, rev); |
1107 node = index_node_existing(self->nt.index, rev); |
1103 if (nt_insert(self, node, (int)rev) == -1) |
1108 if (nt_insert(&self->nt, node, (int)rev) == -1) |
1104 return NULL; |
1109 return NULL; |
1105 Py_RETURN_NONE; |
1110 Py_RETURN_NONE; |
1106 } |
1111 } |
1107 |
1112 |
1108 static int nt_delete_node(nodetree *self, const char *node) |
1113 static int nt_delete_node(nodetree *self, const char *node) |
1115 { |
1120 { |
1116 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */ |
1121 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */ |
1117 self->nodes = NULL; |
1122 self->nodes = NULL; |
1118 |
1123 |
1119 self->index = index; |
1124 self->index = index; |
1120 Py_INCREF(index); |
|
1121 /* The input capacity is in terms of revisions, while the field is in |
1125 /* The input capacity is in terms of revisions, while the field is in |
1122 * terms of nodetree nodes. */ |
1126 * terms of nodetree nodes. */ |
1123 self->capacity = (capacity < 4 ? 4 : capacity / 2); |
1127 self->capacity = (capacity < 4 ? 4 : capacity / 2); |
1124 self->depth = 0; |
1128 self->depth = 0; |
1125 self->splits = 0; |
1129 self->splits = 0; |
1136 return 0; |
1140 return 0; |
1137 } |
1141 } |
1138 |
1142 |
1139 static PyTypeObject indexType; |
1143 static PyTypeObject indexType; |
1140 |
1144 |
1141 static int nt_init_py(nodetree *self, PyObject *args) |
1145 static int ntobj_init(nodetreeObject *self, PyObject *args) |
1142 { |
1146 { |
1143 PyObject *index; |
1147 PyObject *index; |
1144 unsigned capacity; |
1148 unsigned capacity; |
1145 if (!PyArg_ParseTuple(args, "O!I", &indexType, &index, &capacity)) |
1149 if (!PyArg_ParseTuple(args, "O!I", &indexType, &index, &capacity)) |
1146 return -1; |
1150 return -1; |
1147 return nt_init(self, (indexObject*)index, capacity); |
1151 Py_INCREF(index); |
|
1152 return nt_init(&self->nt, (indexObject*)index, capacity); |
1148 } |
1153 } |
1149 |
1154 |
1150 static int nt_partialmatch(nodetree *self, const char *node, |
1155 static int nt_partialmatch(nodetree *self, const char *node, |
1151 Py_ssize_t nodelen) |
1156 Py_ssize_t nodelen) |
1152 { |
1157 { |
1197 */ |
1202 */ |
1198 PyErr_SetString(PyExc_Exception, "broken node tree"); |
1203 PyErr_SetString(PyExc_Exception, "broken node tree"); |
1199 return -3; |
1204 return -3; |
1200 } |
1205 } |
1201 |
1206 |
1202 static PyObject *nt_shortest_py(nodetree *self, PyObject *args) |
1207 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args) |
1203 { |
1208 { |
1204 PyObject *val; |
1209 PyObject *val; |
1205 char *node; |
1210 char *node; |
1206 int length; |
1211 int length; |
1207 |
1212 |
1208 if (!PyArg_ParseTuple(args, "O", &val)) |
1213 if (!PyArg_ParseTuple(args, "O", &val)) |
1209 return NULL; |
1214 return NULL; |
1210 if (node_check(val, &node) == -1) |
1215 if (node_check(val, &node) == -1) |
1211 return NULL; |
1216 return NULL; |
1212 |
1217 |
1213 length = nt_shortest(self, node); |
1218 length = nt_shortest(&self->nt, node); |
1214 if (length == -3) |
1219 if (length == -3) |
1215 return NULL; |
1220 return NULL; |
1216 if (length == -2) { |
1221 if (length == -2) { |
1217 raise_revlog_error(); |
1222 raise_revlog_error(); |
1218 return NULL; |
1223 return NULL; |
1220 return PyInt_FromLong(length); |
1225 return PyInt_FromLong(length); |
1221 } |
1226 } |
1222 |
1227 |
1223 static void nt_dealloc(nodetree *self) |
1228 static void nt_dealloc(nodetree *self) |
1224 { |
1229 { |
1225 Py_XDECREF(self->index); |
|
1226 free(self->nodes); |
1230 free(self->nodes); |
1227 self->nodes = NULL; |
1231 self->nodes = NULL; |
|
1232 } |
|
1233 |
|
1234 static void ntobj_dealloc(nodetreeObject *self) |
|
1235 { |
|
1236 Py_XDECREF(self->nt.index); |
|
1237 nt_dealloc(&self->nt); |
1228 PyObject_Del(self); |
1238 PyObject_Del(self); |
1229 } |
1239 } |
1230 |
1240 |
1231 static PyMethodDef nt_methods[] = { |
1241 static PyMethodDef ntobj_methods[] = { |
1232 {"insert", (PyCFunction)nt_insert_py, METH_VARARGS, |
1242 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS, |
1233 "insert an index entry"}, |
1243 "insert an index entry"}, |
1234 {"shortest", (PyCFunction)nt_shortest_py, METH_VARARGS, |
1244 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS, |
1235 "find length of shortest hex nodeid of a binary ID"}, |
1245 "find length of shortest hex nodeid of a binary ID"}, |
1236 {NULL} /* Sentinel */ |
1246 {NULL} /* Sentinel */ |
1237 }; |
1247 }; |
1238 |
1248 |
1239 static PyTypeObject nodetreeType = { |
1249 static PyTypeObject nodetreeType = { |
1240 PyVarObject_HEAD_INIT(NULL, 0) /* header */ |
1250 PyVarObject_HEAD_INIT(NULL, 0) /* header */ |
1241 "parsers.nodetree", /* tp_name */ |
1251 "parsers.nodetree", /* tp_name */ |
1242 sizeof(nodetree) , /* tp_basicsize */ |
1252 sizeof(nodetree) , /* tp_basicsize */ |
1243 0, /* tp_itemsize */ |
1253 0, /* tp_itemsize */ |
1244 (destructor)nt_dealloc, /* tp_dealloc */ |
1254 (destructor)ntobj_dealloc, /* tp_dealloc */ |
1245 0, /* tp_print */ |
1255 0, /* tp_print */ |
1246 0, /* tp_getattr */ |
1256 0, /* tp_getattr */ |
1247 0, /* tp_setattr */ |
1257 0, /* tp_setattr */ |
1248 0, /* tp_compare */ |
1258 0, /* tp_compare */ |
1249 0, /* tp_repr */ |
1259 0, /* tp_repr */ |
1262 0, /* tp_clear */ |
1272 0, /* tp_clear */ |
1263 0, /* tp_richcompare */ |
1273 0, /* tp_richcompare */ |
1264 0, /* tp_weaklistoffset */ |
1274 0, /* tp_weaklistoffset */ |
1265 0, /* tp_iter */ |
1275 0, /* tp_iter */ |
1266 0, /* tp_iternext */ |
1276 0, /* tp_iternext */ |
1267 nt_methods, /* tp_methods */ |
1277 ntobj_methods, /* tp_methods */ |
1268 0, /* tp_members */ |
1278 0, /* tp_members */ |
1269 0, /* tp_getset */ |
1279 0, /* tp_getset */ |
1270 0, /* tp_base */ |
1280 0, /* tp_base */ |
1271 0, /* tp_dict */ |
1281 0, /* tp_dict */ |
1272 0, /* tp_descr_get */ |
1282 0, /* tp_descr_get */ |
1273 0, /* tp_descr_set */ |
1283 0, /* tp_descr_set */ |
1274 0, /* tp_dictoffset */ |
1284 0, /* tp_dictoffset */ |
1275 (initproc)nt_init_py, /* tp_init */ |
1285 (initproc)ntobj_init, /* tp_init */ |
1276 0, /* tp_alloc */ |
1286 0, /* tp_alloc */ |
1277 }; |
1287 }; |
1278 |
1288 |
1279 static int index_init_nt(indexObject *self) |
1289 static int index_init_nt(indexObject *self) |
1280 { |
1290 { |
1281 if (self->nt == NULL) { |
1291 if (!self->ntinitialized) { |
1282 self->nt = PyObject_New(nodetree, &nodetreeType); |
1292 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) { |
1283 if (self->nt == NULL) { |
1293 nt_dealloc(&self->nt); |
1284 return -1; |
1294 return -1; |
1285 } |
1295 } |
1286 if (nt_init(self->nt, self, (int)self->raw_length) == -1) { |
1296 if (nt_insert(&self->nt, nullid, -1) == -1) { |
1287 nt_dealloc(self->nt); |
1297 nt_dealloc(&self->nt); |
1288 self->nt = NULL; |
|
1289 return -1; |
1298 return -1; |
1290 } |
1299 } |
1291 if (nt_insert(self->nt, nullid, -1) == -1) { |
1300 self->ntinitialized = 1; |
1292 nt_dealloc(self->nt); |
|
1293 self->nt = NULL; |
|
1294 return -1; |
|
1295 } |
|
1296 self->ntrev = (int)index_length(self); |
1301 self->ntrev = (int)index_length(self); |
1297 self->ntlookups = 1; |
1302 self->ntlookups = 1; |
1298 self->ntmisses = 0; |
1303 self->ntmisses = 0; |
1299 } |
1304 } |
1300 return 0; |
1305 return 0; |
1314 |
1319 |
1315 if (index_init_nt(self) == -1) |
1320 if (index_init_nt(self) == -1) |
1316 return -3; |
1321 return -3; |
1317 |
1322 |
1318 self->ntlookups++; |
1323 self->ntlookups++; |
1319 rev = nt_find(self->nt, node, nodelen, 0); |
1324 rev = nt_find(&self->nt, node, nodelen, 0); |
1320 if (rev >= -1) |
1325 if (rev >= -1) |
1321 return rev; |
1326 return rev; |
1322 |
1327 |
1323 /* |
1328 /* |
1324 * For the first handful of lookups, we scan the entire index, |
1329 * For the first handful of lookups, we scan the entire index, |
1333 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
1338 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
1334 const char *n = index_node_existing(self, rev); |
1339 const char *n = index_node_existing(self, rev); |
1335 if (n == NULL) |
1340 if (n == NULL) |
1336 return -3; |
1341 return -3; |
1337 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) { |
1342 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) { |
1338 if (nt_insert(self->nt, n, rev) == -1) |
1343 if (nt_insert(&self->nt, n, rev) == -1) |
1339 return -3; |
1344 return -3; |
1340 break; |
1345 break; |
1341 } |
1346 } |
1342 } |
1347 } |
1343 } else { |
1348 } else { |
1344 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
1349 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
1345 const char *n = index_node_existing(self, rev); |
1350 const char *n = index_node_existing(self, rev); |
1346 if (n == NULL) |
1351 if (n == NULL) |
1347 return -3; |
1352 return -3; |
1348 if (nt_insert(self->nt, n, rev) == -1) { |
1353 if (nt_insert(&self->nt, n, rev) == -1) { |
1349 self->ntrev = rev + 1; |
1354 self->ntrev = rev + 1; |
1350 return -3; |
1355 return -3; |
1351 } |
1356 } |
1352 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) { |
1357 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) { |
1353 break; |
1358 break; |
1387 if (self->ntrev > 0) { |
1392 if (self->ntrev > 0) { |
1388 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
1393 for (rev = self->ntrev - 1; rev >= 0; rev--) { |
1389 const char *n = index_node_existing(self, rev); |
1394 const char *n = index_node_existing(self, rev); |
1390 if (n == NULL) |
1395 if (n == NULL) |
1391 return -1; |
1396 return -1; |
1392 if (nt_insert(self->nt, n, rev) == -1) |
1397 if (nt_insert(&self->nt, n, rev) == -1) |
1393 return -1; |
1398 return -1; |
1394 } |
1399 } |
1395 self->ntrev = -1; |
1400 self->ntrev = -1; |
1396 } |
1401 } |
1397 return 0; |
1402 return 0; |
1884 |
1889 |
1885 for (i = start; i < len; i++) { |
1890 for (i = start; i < len; i++) { |
1886 PyObject *tuple = PyList_GET_ITEM(self->added, i); |
1891 PyObject *tuple = PyList_GET_ITEM(self->added, i); |
1887 PyObject *node = PyTuple_GET_ITEM(tuple, 7); |
1892 PyObject *node = PyTuple_GET_ITEM(tuple, 7); |
1888 |
1893 |
1889 nt_delete_node(self->nt, PyBytes_AS_STRING(node)); |
1894 nt_delete_node(&self->nt, PyBytes_AS_STRING(node)); |
1890 } |
1895 } |
1891 |
1896 |
1892 if (start == 0) |
1897 if (start == 0) |
1893 Py_CLEAR(self->added); |
1898 Py_CLEAR(self->added); |
1894 } |
1899 } |
1935 "revlog index deletion indices are invalid"); |
1940 "revlog index deletion indices are invalid"); |
1936 return -1; |
1941 return -1; |
1937 } |
1942 } |
1938 |
1943 |
1939 if (start < self->length) { |
1944 if (start < self->length) { |
1940 if (self->nt) { |
1945 if (self->ntinitialized) { |
1941 Py_ssize_t i; |
1946 Py_ssize_t i; |
1942 |
1947 |
1943 for (i = start + 1; i < self->length; i++) { |
1948 for (i = start + 1; i < self->length; i++) { |
1944 const char *node = index_node_existing(self, i); |
1949 const char *node = index_node_existing(self, i); |
1945 if (node == NULL) |
1950 if (node == NULL) |
1946 return -1; |
1951 return -1; |
1947 |
1952 |
1948 nt_delete_node(self->nt, node); |
1953 nt_delete_node(&self->nt, node); |
1949 } |
1954 } |
1950 if (self->added) |
1955 if (self->added) |
1951 index_invalidate_added(self, 0); |
1956 index_invalidate_added(self, 0); |
1952 if (self->ntrev > start) |
1957 if (self->ntrev > start) |
1953 self->ntrev = (int)start; |
1958 self->ntrev = (int)start; |
1995 |
2000 |
1996 if (node_check(item, &node) == -1) |
2001 if (node_check(item, &node) == -1) |
1997 return -1; |
2002 return -1; |
1998 |
2003 |
1999 if (value == NULL) |
2004 if (value == NULL) |
2000 return self->nt ? nt_delete_node(self->nt, node) : 0; |
2005 return self->ntinitialized ? nt_delete_node(&self->nt, node) : 0; |
2001 rev = PyInt_AsLong(value); |
2006 rev = PyInt_AsLong(value); |
2002 if (rev > INT_MAX || rev < 0) { |
2007 if (rev > INT_MAX || rev < 0) { |
2003 if (!PyErr_Occurred()) |
2008 if (!PyErr_Occurred()) |
2004 PyErr_SetString(PyExc_ValueError, "rev out of range"); |
2009 PyErr_SetString(PyExc_ValueError, "rev out of range"); |
2005 return -1; |
2010 return -1; |
2006 } |
2011 } |
2007 |
2012 |
2008 if (index_init_nt(self) == -1) |
2013 if (index_init_nt(self) == -1) |
2009 return -1; |
2014 return -1; |
2010 return nt_insert(self->nt, node, (int)rev); |
2015 return nt_insert(&self->nt, node, (int)rev); |
2011 } |
2016 } |
2012 |
2017 |
2013 /* |
2018 /* |
2014 * Find all RevlogNG entries in an index that has inline data. Update |
2019 * Find all RevlogNG entries in an index that has inline data. Update |
2015 * the optional "offsets" table with those entries. |
2020 * the optional "offsets" table with those entries. |
2054 self->data = NULL; |
2059 self->data = NULL; |
2055 memset(&self->buf, 0, sizeof(self->buf)); |
2060 memset(&self->buf, 0, sizeof(self->buf)); |
2056 self->headrevs = NULL; |
2061 self->headrevs = NULL; |
2057 self->filteredrevs = Py_None; |
2062 self->filteredrevs = Py_None; |
2058 Py_INCREF(Py_None); |
2063 Py_INCREF(Py_None); |
2059 self->nt = NULL; |
2064 self->ntinitialized = 0; |
2060 self->offsets = NULL; |
2065 self->offsets = NULL; |
2061 |
2066 |
2062 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj)) |
2067 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj)) |
2063 return -1; |
2068 return -1; |
2064 if (!PyObject_CheckBuffer(data_obj)) { |
2069 if (!PyObject_CheckBuffer(data_obj)) { |
2116 } |
2121 } |
2117 if (self->offsets) { |
2122 if (self->offsets) { |
2118 PyMem_Free((void *)self->offsets); |
2123 PyMem_Free((void *)self->offsets); |
2119 self->offsets = NULL; |
2124 self->offsets = NULL; |
2120 } |
2125 } |
2121 if (self->nt != NULL) { |
2126 if (self->ntinitialized) { |
2122 nt_dealloc(self->nt); |
2127 nt_dealloc(&self->nt); |
2123 } |
2128 } |
2124 self->nt = NULL; |
2129 self->ntinitialized = 0; |
2125 Py_CLEAR(self->headrevs); |
2130 Py_CLEAR(self->headrevs); |
2126 } |
2131 } |
2127 |
2132 |
2128 static PyObject *index_clearcaches(indexObject *self) |
2133 static PyObject *index_clearcaches(indexObject *self) |
2129 { |
2134 { |
2141 PyBuffer_Release(&self->buf); |
2146 PyBuffer_Release(&self->buf); |
2142 memset(&self->buf, 0, sizeof(self->buf)); |
2147 memset(&self->buf, 0, sizeof(self->buf)); |
2143 } |
2148 } |
2144 Py_XDECREF(self->data); |
2149 Py_XDECREF(self->data); |
2145 Py_XDECREF(self->added); |
2150 Py_XDECREF(self->added); |
2146 Py_XDECREF(self->nt); |
|
2147 PyObject_Del(self); |
2151 PyObject_Del(self); |
2148 } |
2152 } |
2149 |
2153 |
2150 static PySequenceMethods index_sequence_methods = { |
2154 static PySequenceMethods index_sequence_methods = { |
2151 (lenfunc)index_length, /* sq_length */ |
2155 (lenfunc)index_length, /* sq_length */ |