[Zodb-checkins] CVS: Zope/lib/python/BTrees - BTreeTemplate.c:1.27

Jim Fulton jim@zope.com
Tue, 28 May 2002 18:15:26 -0400


Update of /cvs-repository/Zope/lib/python/BTrees
In directory cvs.zope.org:/tmp/cvs-serv3856

Modified Files:
	BTreeTemplate.c 
Log Message:
Fixed a bug that caused BTree item iteration to sometimes fail when
keys at the beginning of the BTree were deleted.


=== Zope/lib/python/BTrees/BTreeTemplate.c 1.26 => 1.27 ===
     }
 
-  /* 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 @@
       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 @@
                   changed=1;
                 }
             }          
-          else
+          else                  /* Bucket */
             {
               if (BUCKET(d->value)->len > MAX_BUCKET_SIZE(d->value))
                 {
@@ -441,38 +449,46 @@
               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;
             }
+          
         }
     }