Commit 1e285a3c authored by Tim Peters's avatar Tim Peters

Merge rev 27796 from 3.3 branch.

Merge revs 27788 and 27795 from Zope trunk.

See Collector #1350.

ghostify() and unghostify() detect one form of thread insanity
now.  In a debug build, they abort the process if it happens.
In a release build, unghostify() raises SystemError, and
ghostify() ignores it (ghostify() can't raise an exception).
parent 2762118d
......@@ -14,6 +14,25 @@ which objects did it reference? what kind of object was it?).
ZODB/test/testfsoids.py is a tutorial doctest.
What's new in ZODB3 3.3.1?
==========================
Release date: xx-xxx-2004
persistent
----------
Collector #1350: ZODB has a default one-thread-per-connection model, and
two threads should never do operations on a single connection
simultaneously. However, ZODB can't detect violations, and this happened
in an early stage of Zope 2.8 development. The low-level ``ghostify()``
and ``unghostify()`` routines in ``cPerisistence.c`` were changed to give
some help in detecting this when it happens. In a debug build, both abort
the process if thread interference is detected. This is extreme, but
impossible to overlook. In a release build, ``unghostify()`` raises
``SystemError`` if thread damage is detected; ``ghostify()`` ignores the
problem in a release build (``ghostify()`` is supposed to be so simple that
it "can't fail").
What's new in ZODB3 3.3?
========================
Release date: 06-Oct-2004
......
......@@ -58,6 +58,24 @@ init_strings(void)
return 0;
}
#ifdef Py_DEBUG
static void
fatal_1350(cPersistentObject *self, const char *caller, const char *detail)
{
char buf[1000];
PyOS_snprintf(buf, sizeof(buf),
"cPersistence.c %s(): object at %p with type %.200s\n"
"%s.\n"
"The only known cause is multiple threads trying to ghost and\n"
"unghost the object simultaneously.\n"
"That's not legal, but ZODB can't stop it.\n"
"See Collector #1350.\n",
caller, self, self->ob_type->tp_name, detail);
Py_FatalError(buf);
}
#endif
static void ghostify(cPersistentObject*);
/* Load the state of the object, unghostifying it. Upon success, return 1.
......@@ -88,6 +106,18 @@ unghostify(cPersistentObject *self)
}
self->state = cPersistent_UPTODATE_STATE;
Py_DECREF(r);
if (self->cache && self->ring.r_next == NULL) {
#ifdef Py_DEBUG
fatal_1350(self, "unghostify",
"is not in the cache despite that we just "
"unghostified it");
#else
PyErr_Format(PyExc_SystemError, "object at %p with type "
"%.200s not in the cache despite that we just "
"unghostified it", self, self->ob_type->tp_name);
return -1;
#endif
}
}
return 1;
}
......@@ -134,13 +164,19 @@ ghostify(cPersistentObject *self)
return;
}
/* If the cache is still active, we must unlink the object. */
if (self->ring.r_next) {
/* if we're ghostifying an object, we better have some non-ghosts */
if (self->ring.r_next == NULL) {
/* There's no way to raise an error in this routine. */
#ifdef Py_DEBUG
fatal_1350(self, "ghostify", "claims to be in a cache but isn't");
#else
return;
#endif
}
/* If we're ghostifying an object, we better have some non-ghosts. */
assert(self->cache->non_ghost_count > 0);
self->cache->non_ghost_count--;
ring_del(&self->ring);
}
self->state = cPersistent_GHOST_STATE;
dictptr = _PyObject_GetDictPtr((PyObject *)self);
if (dictptr && *dictptr) {
......
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