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 @@
****************************************************************************/
#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
......@@ -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)
{
d=self->data+i;
......@@ -370,20 +372,26 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
else max=i;
}
d=self->data+min;
if (SameType_Check(self, d->value))
grew= _BTree_set( BTREE(d->value), keyarg, value, unique, noval);
else
grew=_bucket_set(BUCKET(d->value), keyarg, value, unique, noval,
&bchanged);
d=self->data+min; /* Get item */
if (SameType_Check(self, d->value)) /* Child is a BTree */
grew = _BTree_set( BTREE(d->value), keyarg, value, unique, noval);
else /* Child is a bucket */
grew = _bucket_set(BUCKET(d->value), keyarg, value, unique, noval,
&bchanged);
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)
{
bchanged=1; /* A bucket changed size */
if (value) /* got bigger */
bchanged=1; /* A bucket changed size */
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))
{
......@@ -391,7 +399,7 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
changed=1;
}
}
else
else /* Bucket */
{
if (BUCKET(d->value)->len > MAX_BUCKET_SIZE(d->value))
{
......@@ -441,38 +449,46 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
if (min < self->len)
memmove(d, d+1, (self->len-min)*sizeof(BTreeItem));
if (! min)
{
if (self->len)
{ /* We just deleted our first child, so we need to
adjust our first bucket. */
if (SameType_Check(self, self->data->value))
{
UNLESS (PER_USE(BTREE(self->data->value))) goto err;
ASSIGNB(self->firstbucket,
BTREE(self->data->value)->firstbucket);
Py_XINCREF(self->firstbucket);
PER_ALLOW_DEACTIVATION(BTREE(self->data->value));
PER_ACCESSED(BTREE(self->data->value));
}
else
{
ASSIGNB(self->firstbucket,
BUCKET(self->data->value));
Py_INCREF(self->firstbucket);
}
/* We can toss our first key now */
DECREF_KEY(self->data->key);
changed=1;
}
if (min == 0 && grew > 1)
/* The first bucket got deleted by us or a child.
If grew is > 1 then either we deleted the first one and
incremented grew ourself (just above) or
a child deleted it's first bucket and nobody could
adjust the pervious bucket's pointer, because there
were no previous buckets. Thus, it *must* be the first!
*/
{
if (self->len)
{ /* We just deleted our first child, so we need to
adjust our first bucket. */
if (SameType_Check(self, self->data->value))
{
UNLESS (PER_USE(BTREE(self->data->value))) goto err;
ASSIGNB(self->firstbucket,
BTREE(self->data->value)->firstbucket);
Py_XINCREF(self->firstbucket);
PER_ALLOW_DEACTIVATION(BTREE(self->data->value));
PER_ACCESSED(BTREE(self->data->value));
}
else
else
{
Py_XDECREF(self->firstbucket);
self->firstbucket = 0;
ASSIGNB(self->firstbucket,
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):
def _noneraises(self):
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):
def setUp(self):
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