Mercurial > hg
comparison mercurial/cext/revlog.c @ 39291:9f097214fbf3
index: embed nodetree in index object to avoid reference cycle
Since the index has a reference to a nodetree and the nodetree has a
reference back to the index, there is a reference cycle, so the index
(and its nodetree) can never be freed. This patch fixes that by making
"nodetree" a plan C struct that the index can embed, and also
introduces a new "nodetreeObject" that is a Python type wrapping the
nodetree struct.
Thanks to Yuya for noticing this and for suggesting the solution.
All tests passed on the first attempt once it compiled (I guess C is
like Haskell in this regard?).
Differential Revision: https://phab.mercurial-scm.org/D4372
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 24 Aug 2018 08:45:18 -0700 |
parents | 66f046116105 |
children | b69fbdd77c40 |
comparison
equal
deleted
inserted
replaced
39290:286a666365ec | 39291:9f097214fbf3 |
---|---|
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 }; |
331 } | 336 } |
332 | 337 |
333 if (PyList_Append(self->added, obj) == -1) | 338 if (PyList_Append(self->added, obj) == -1) |
334 return NULL; | 339 return NULL; |
335 | 340 |
336 if (self->nt) | 341 if (self->ntinitialized) |
337 nt_insert(self->nt, node, (int)len); | 342 nt_insert(&self->nt, node, (int)len); |
338 | 343 |
339 Py_CLEAR(self->headrevs); | 344 Py_CLEAR(self->headrevs); |
340 Py_RETURN_NONE; | 345 Py_RETURN_NONE; |
341 } | 346 } |
342 | 347 |
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; |
1427 | 1432 |
1428 if (index_init_nt(self) == -1) | 1433 if (index_init_nt(self) == -1) |
1429 return NULL; | 1434 return NULL; |
1430 if (index_populate_nt(self) == -1) | 1435 if (index_populate_nt(self) == -1) |
1431 return NULL; | 1436 return NULL; |
1432 rev = nt_partialmatch(self->nt, node, nodelen); | 1437 rev = nt_partialmatch(&self->nt, node, nodelen); |
1433 | 1438 |
1434 switch (rev) { | 1439 switch (rev) { |
1435 case -4: | 1440 case -4: |
1436 raise_revlog_error(); | 1441 raise_revlog_error(); |
1437 return NULL; | 1442 return NULL; |
1462 self->ntlookups++; | 1467 self->ntlookups++; |
1463 if (index_init_nt(self) == -1) | 1468 if (index_init_nt(self) == -1) |
1464 return NULL; | 1469 return NULL; |
1465 if (index_populate_nt(self) == -1) | 1470 if (index_populate_nt(self) == -1) |
1466 return NULL; | 1471 return NULL; |
1467 length = nt_shortest(self->nt, node); | 1472 length = nt_shortest(&self->nt, node); |
1468 if (length == -3) | 1473 if (length == -3) |
1469 return NULL; | 1474 return NULL; |
1470 if (length == -2) { | 1475 if (length == -2) { |
1471 raise_revlog_error(); | 1476 raise_revlog_error(); |
1472 return NULL; | 1477 return NULL; |
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; |
1962 self->raw_length = start; | 1967 self->raw_length = start; |
1963 } | 1968 } |
1964 goto done; | 1969 goto done; |
1965 } | 1970 } |
1966 | 1971 |
1967 if (self->nt) { | 1972 if (self->ntinitialized) { |
1968 index_invalidate_added(self, start - self->length); | 1973 index_invalidate_added(self, start - self->length); |
1969 if (self->ntrev > start) | 1974 if (self->ntrev > start) |
1970 self->ntrev = (int)start; | 1975 self->ntrev = (int)start; |
1971 } | 1976 } |
1972 if (self->added) | 1977 if (self->added) |
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 */ |