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

Tim Peters tim.one@comcast.net
Mon, 17 Jun 2002 16:02:39 -0400


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

Modified Files:
	BTreeTemplate.c 
Log Message:
_BTree_clear():  Made the Zope2 and Zope3 versions as similar as possible.


=== Zope/lib/python/BTrees/BTreeTemplate.c 1.57 => 1.58 ===
 ** _BTree_clear
 **
-** Clears out all of the values in the BTree
+** Clears out all of the values in the BTree (firstbucket, keys, and children);
+** leaving self an empty BTree.
 **
 ** Arguments:	self	The BTree
 **
 ** Returns:	 0	on success
 **		-1	on failure
-*/
+**
+** Internal:  Deallocation order is important.  The danger is that a long
+** list of buckets may get freed "at once" via decref'ing the first bucket,
+** in which case a chain of consequenct Py_DECREF calls may blow the stack.
+** Luckily, every bucket has a refcount of at least two, one due to being a
+** BTree node's child, and another either because it's not the first bucket in
+** the chain (so the preceding bucket points to it), or because firstbucket
+** points to it.  By clearing in the natural depth-first, left-to-right
+** order, the BTree->bucket child pointers prevent Py_DECREF(bucket->next)
+** calls from freeing bucket->next, and the maximum stack depth is equal
+** to the height of the tree.
+**/
 static int
 _BTree_clear(BTree *self)
 {
-  int i, l;
-
-  /* The order in which we dealocate, from "top to bottom" is critical
-     to prevent memory memory errors when the deallocation stack
-     becomes huge when dealocating use linked lists of buckets.
-  */
+    const int len = self->len;
 
-  if (self->firstbucket)
-    {
-      ASSERT(self->firstbucket->ob_refcnt > 0,
-             "Invalid firstbucket pointer", -1);
-      Py_DECREF(self->firstbucket);
-      self->firstbucket=NULL;
+    if (self->firstbucket) {
+	ASSERT(self->firstbucket->ob_refcnt > 1,
+	       "Invalid firstbucket pointer", -1);
+	Py_DECREF(self->firstbucket);
+	self->firstbucket = NULL;
     }
 
-  for (l=self->len, i=0; i < l; i++)
-    {
-      if (i)
-        {
-          DECREF_KEY(self->data[i].key);
-        }
-      Py_DECREF(self->data[i].child);
-    }
-  self->len=0;
+    if (self->data) {
+        int i;
+        if (len > 0) { /* 0 is special because key 0 is trash */
+            Py_DECREF(self->data[0].child);
+	}
 
-  if (self->data)
-    {
-      free(self->data);
-      self->data=0;
-      self->size=0;
+        for (i = 1; i < len; i++) {
+	    DECREF_KEY(self->data[i].key);
+            Py_DECREF(self->data[i].child);
+        }
+	free(self->data);
+	self->data = NULL;
     }
 
-  return 0;
+    self->len = self->size = 0;
+    return 0;
 }
 
 #ifdef PERSISTENT