Commit 50e4a04b authored by Jim Fulton's avatar Jim Fulton

Fixed a bug that caused BTree item iteration to sometimes fail when

keys at the beginning of the BTree were deleted.
parent e1e996a8
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
****************************************************************************/ ****************************************************************************/
#define BTREETEMPLATE_C "$Id: BTreeTemplate.c,v 1.26 2002/03/27 10:14:01 htrd Exp $\n" #define BTREETEMPLATE_C "$Id: BTreeTemplate.c,v 1.27 2002/05/28 22:15:25 jim Exp $\n"
/* /*
** _BTree_get ** _BTree_get
...@@ -356,7 +356,9 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -356,7 +356,9 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
} }
} }
/* Binary search to find insertion point */ /* Binary search to find insertion point.
min will be set to the index of the child that might have the key.
*/
for (min=0, max=self->len, i=max/2; max-min > 1; i=(max+min)/2) for (min=0, max=self->len, i=max/2; max-min > 1; i=(max+min)/2)
{ {
d=self->data+i; d=self->data+i;
...@@ -370,20 +372,26 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -370,20 +372,26 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
else max=i; else max=i;
} }
d=self->data+min; d=self->data+min; /* Get item */
if (SameType_Check(self, d->value)) if (SameType_Check(self, d->value)) /* Child is a BTree */
grew= _BTree_set( BTREE(d->value), keyarg, value, unique, noval); grew = _BTree_set( BTREE(d->value), keyarg, value, unique, noval);
else else /* Child is a bucket */
grew=_bucket_set(BUCKET(d->value), keyarg, value, unique, noval, grew = _bucket_set(BUCKET(d->value), keyarg, value, unique, noval,
&bchanged); &bchanged);
if (grew < 0) goto err; if (grew < 0) goto err;
/* grew >0 if we changed the length of the BTree.
If we got smaller and a a bucket got deleted, then
grew might be >1 to indicate that we need to adjust previous
bucket pointers, if we can.
*/
if (grew) if (grew)
{ {
bchanged=1; /* A bucket changed size */ bchanged=1; /* A bucket changed size */
if (value) /* got bigger */ if (value) /* got bigger, check for max size exceeded */
{ {
if (SameType_Check(self, d->value)) if (SameType_Check(self, d->value)) /* BTree */
{ {
if (BTREE(d->value)->len > MAX_BTREE_SIZE(d->value)) if (BTREE(d->value)->len > MAX_BTREE_SIZE(d->value))
{ {
...@@ -391,7 +399,7 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -391,7 +399,7 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
changed=1; changed=1;
} }
} }
else else /* Bucket */
{ {
if (BUCKET(d->value)->len > MAX_BUCKET_SIZE(d->value)) if (BUCKET(d->value)->len > MAX_BUCKET_SIZE(d->value))
{ {
...@@ -441,38 +449,46 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -441,38 +449,46 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
if (min < self->len) if (min < self->len)
memmove(d, d+1, (self->len-min)*sizeof(BTreeItem)); memmove(d, d+1, (self->len-min)*sizeof(BTreeItem));
if (! min) changed=1;
{ }
if (self->len)
{ /* We just deleted our first child, so we need to if (min == 0 && grew > 1)
adjust our first bucket. */ /* The first bucket got deleted by us or a child.
if (SameType_Check(self, self->data->value)) If grew is > 1 then either we deleted the first one and
{ incremented grew ourself (just above) or
UNLESS (PER_USE(BTREE(self->data->value))) goto err; a child deleted it's first bucket and nobody could
ASSIGNB(self->firstbucket, adjust the pervious bucket's pointer, because there
BTREE(self->data->value)->firstbucket); were no previous buckets. Thus, it *must* be the first!
Py_XINCREF(self->firstbucket); */
PER_ALLOW_DEACTIVATION(BTREE(self->data->value)); {
PER_ACCESSED(BTREE(self->data->value)); if (self->len)
} { /* We just deleted our first child, so we need to
else adjust our first bucket. */
{ if (SameType_Check(self, self->data->value))
ASSIGNB(self->firstbucket, {
BUCKET(self->data->value)); UNLESS (PER_USE(BTREE(self->data->value))) goto err;
Py_INCREF(self->firstbucket); ASSIGNB(self->firstbucket,
} BTREE(self->data->value)->firstbucket);
/* We can toss our first key now */ Py_XINCREF(self->firstbucket);
DECREF_KEY(self->data->key); PER_ALLOW_DEACTIVATION(BTREE(self->data->value));
PER_ACCESSED(BTREE(self->data->value));
} }
else else
{ {
Py_XDECREF(self->firstbucket); ASSIGNB(self->firstbucket,
self->firstbucket = 0; BUCKET(self->data->value));
Py_INCREF(self->firstbucket);
} }
/* We can toss our first key now */
DECREF_KEY(self->data->key);
}
else
{
Py_XDECREF(self->firstbucket);
self->firstbucket = 0;
} }
changed=1;
} }
} }
} }
......
...@@ -607,6 +607,16 @@ class TestIOBTrees(BTreeTests, TestCase): ...@@ -607,6 +607,16 @@ class TestIOBTrees(BTreeTests, TestCase):
def _noneraises(self): def _noneraises(self):
self.t[None] = 1 self.t[None] = 1
def testEmptyFirstBucketReportedByGuido(self):
b = self.t
for i in xrange(29972): # reduce to 29971 and it works
b[i] = i
for i in xrange(30): # reduce to 29 and it works
del b[i]
b[i+40000] = i
self.assertEqual(b.keys()[0], 30)
class TestOOBTrees(BTreeTests, TestCase): class TestOOBTrees(BTreeTests, TestCase):
def setUp(self): def setUp(self):
self.t = OOBTree() self.t = OOBTree()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment