[Zodb-checkins] CVS: Zope3/lib/python/Persistence/BTrees - BucketTemplate.c:1.1.2.29
Tim Peters
tim.one@comcast.net
Sat, 8 Jun 2002 23:00:05 -0400
Update of /cvs-repository/Zope3/lib/python/Persistence/BTrees
In directory cvs.zope.org:/tmp/cvs-serv18502
Modified Files:
Tag: Zope-3x-branch
BucketTemplate.c
Log Message:
Porting changes from the trunk.
Reworked _bucket_set():
+ Documented the arguments.
+ Used BUCKET_SEARCH.
+ Vastly reduced nesting.
+ Changed the "*changed" argument to get set true whenever PER_CHANGED
is called, i.e. whenever the bucket mutates. The purpose of *changed
wasn't documented, and its only use was in the BTree set routine, which
is known to have at least one bug. So it wasn't clear what the purpose
of *changed was. What it did do is get set true if and only if the
key was found in the bucket and its value was replaced, and I couldn't
imagine a plausible reason for why the BTree set routine could care
about that alone (all other calls to _bucket_set pass NULL, so there
were no other clues).
+ Fixed all places where error returns didn't finish the persistence
dance.
=== Zope3/lib/python/Persistence/BTrees/BucketTemplate.c 1.1.2.28 => 1.1.2.29 ===
/*
-** _bucket_set
+** _bucket_set: Assign a value to a key in a bucket, delete a key+value
+** pair, or just insert a key.
**
-** Assign a value into a bucket
+** Arguments
+** self The bucket
+** keyarg The key to look for
+** v The value to associate with key; NULL means delete the key.
+** If NULL, it's an error (KeyError) if the key isn't present.
+** Note that if this is a set bucket, and you want to insert
+** a new set element, v must be non-NULL although its exact
+** value will be ignored. Passing Py_None is good for this.
+** unique Boolean; when true, don't replace the value if the key is
+** already present.
+** noval Boolean; when true, operate on keys only (ignore values)
+** changed ignored on input
**
-** Arguments: self The bucket
-** key The key of the object to insert
-** v The value of the object to insert
-** unique Inserting a unique key
-**
-** Returns: -1 on error
-** 0 on success with a replacement
-** 1 on success with a new value (growth)
+** Return
+** -1 on error
+** 0 on success and the # of bucket entries didn't change
+** 1 on success and the # of bucket entries did change
+** *changed If non-NULL, set to 1 on any mutation of the bucket.
*/
static int
_bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
int unique, int noval, int *changed)
{
- int min, max, i, l, cmp, copied=1;
- KEY_TYPE key;
-
- COPY_KEY_FROM_ARG(key, keyarg, copied);
- UNLESS(copied) return -1;
-
- PyPersist_INCREF(self);
- if (!PyPersist_IS_STICKY(self))
- return -1;
-
- for (min=0, max=l=self->len, i=max/2; i != l; l=i, i=(min+max)/2)
- {
- TEST_KEY_SET_OR(cmp, self->keys[i], key) goto err;
- if (cmp < 0) min=i;
- else if (cmp==0)
- {
- if (v) /* Assign value to key */
- {
- if (! unique && ! noval && self->values)
- {
- VALUE_TYPE value;
-
- COPY_VALUE_FROM_ARG(value, v, copied);
- UNLESS(copied) return -1;
-
+ int i, cmp;
+ KEY_TYPE key;
+ int result = -1; /* until proven innocent */
+ int copied = 1;
+
+ COPY_KEY_FROM_ARG(key, keyarg, copied);
+ UNLESS(copied) return -1;
+
+ PyPersist_INCREF(self);
+ if (!PyPersist_IS_STICKY(self))
+ return -1;
+
+ BUCKET_SEARCH(i, cmp, self, key, goto Done);
+ if (cmp == 0) {
+ VALUE_TYPE value;
+ /* The key exists, at index i. */
+
+ if (v) {
+ /* The key exists at index i, and there's a new value.
+ * If unique, we're not supposed to replace it. If noval, or this
+ * is a set bucket (self->values is NULL), there's nothing to do.
+ */
+ if (unique || noval || self->values == NULL) {
+ result = 0;
+ goto Done;
+ }
+
+ /* The key exists at index i, and we need to replace the value. */
+ COPY_VALUE_FROM_ARG(value, v, copied);
+ UNLESS(copied) goto Done;
#ifdef VALUE_SAME
- if (VALUE_SAME(self->values[i], value))
- { /* short-circuit if no change */
- PyPersist_DECREF(self);
- PyPersist_SetATime(self);
- return 0;
- }
+ /* short-circuit if no change */
+ if (VALUE_SAME(self->values[i], value)) {
+ result = 0;
+ goto Done;
+ }
#endif
- if (changed) *changed=1;
- DECREF_VALUE(self->values[i]);
- COPY_VALUE(self->values[i], value);
- INCREF_VALUE(self->values[i]);
- if (PER_CHANGED(self) < 0) goto err;
- }
- PyPersist_DECREF(self);
- PyPersist_SetATime(self);
- return 0;
- }
- else /* There's no value so remove the item */
- {
- self->len--;
-
- DECREF_KEY(self->keys[i]);
- if (i < self->len)
- memmove(self->keys+i, self->keys+i+1,
- sizeof(KEY_TYPE)*(self->len-i));
-
- if (self->values && ! noval)
- {
- DECREF_VALUE(self->values[i]);
- if (i < self->len)
- memmove(self->values+i, self->values+i+1,
- sizeof(VALUE_TYPE)*(self->len-i));
-
- }
-
- if (! self->len)
- {
- self->size=0;
- free(self->keys);
- self->keys=NULL;
- if (self->values)
- {
- free(self->values);
- self->values=NULL;
- }
- }
-
- if (PER_CHANGED(self) < 0) goto err;
- PyPersist_DECREF(self);
- PyPersist_SetATime(self);
- return 1;
- }
- }
- else max=i;
+ if (changed)
+ *changed = 1;
+ DECREF_VALUE(self->values[i]);
+ COPY_VALUE(self->values[i], value);
+ INCREF_VALUE(self->values[i]);
+ if (PER_CHANGED(self) >= 0)
+ result = 0;
+ goto Done;
+ }
+
+ /* The key exists at index i, and should be deleted. */
+ DECREF_KEY(self->keys[i]);
+ self->len--;
+ if (i < self->len)
+ memmove(self->keys + i, self->keys + i+1,
+ sizeof(KEY_TYPE)*(self->len - i));
+
+ if (self->values) {
+ DECREF_VALUE(self->values[i]);
+ if (i < self->len)
+ memmove(self->values + i, self->values + i+1,
+ sizeof(VALUE_TYPE)*(self->len - i));
+ }
+
+ if (! self->len) {
+ self->size = 0;
+ free(self->keys);
+ self->keys = NULL;
+ if (self->values) {
+ free(self->values);
+ self->values = NULL;
+ }
+ }
+
+ if (changed)
+ *changed = 1;
+ if (PER_CHANGED(self) >= 0)
+ result = 1;
+ goto Done;
}
- if (!v)
- {
- PyErr_SetObject(PyExc_KeyError, keyarg);
- goto err;
+ /* The key doesn't exist, and belongs at index i. */
+ if (!v) {
+ /* Can't delete a non-existent key. */
+ PyErr_SetObject(PyExc_KeyError, keyarg);
+ goto Done;
}
- if (self->len==self->size && Bucket_grow(self, -1, noval) < 0) goto err;
-
- if (max != i) i++;
-
- if (self->len > i)
- {
- memmove(self->keys+i+1, self->keys+i,
- sizeof(KEY_TYPE)*(self->len-i));
- UNLESS (noval)
- memmove(self->values+i+1, self->values+i,
- sizeof(VALUE_TYPE)*(self->len-i));
+ /* The key doesn't exist and should be inserted at index i. */
+ if (self->len == self->size && Bucket_grow(self, -1, noval) < 0)
+ goto Done;
+
+ if (self->len > i) {
+ memmove(self->keys + i+1, self->keys + i,
+ sizeof(KEY_TYPE)*(self->len - i));
+ if (self->values) {
+ memmove(self->values + i+1, self->values + i,
+ sizeof(VALUE_TYPE)*(self->len - i));
+ }
}
+ COPY_KEY(self->keys[i], key);
+ INCREF_KEY(self->keys[i]);
- COPY_KEY(self->keys[i], key);
- INCREF_KEY(self->keys[i]);
-
- UNLESS (noval)
- {
- COPY_VALUE_FROM_ARG(self->values[i], v, copied);
- UNLESS(copied) return -1;
- INCREF_VALUE(self->values[i]);
+ if (! noval) {
+ COPY_VALUE_FROM_ARG(self->values[i], v, copied);
+ UNLESS(copied) return -1;
+ INCREF_VALUE(self->values[i]);
}
- self->len++;
-
- if (PER_CHANGED(self) < 0) goto err;
- PyPersist_DECREF(self);
- PyPersist_SetATime(self);
- return 1;
-
-err:
- PyPersist_DECREF(self);
- PyPersist_SetATime(self);
- return -1;
+ self->len++;
+ if (changed)
+ *changed = 1;
+ if (PER_CHANGED(self) >= 0)
+ result = 1;
+
+Done:
+ PyPersist_DECREF(self);
+ PyPersist_SetATime(self);
+ return result;
}
/*