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 */