[ZODB-Dev] Can __setstate__ trigger an RCE?
Tim Peters
tim at zope.com
Tue Jul 6 14:49:53 EDT 2004
[Christian Robottom Reis]
> I'm still trying to track down a problem that occurs with read conflicts
> in IndexedCatalog when using ZODB without MVCC enabled. The issue is that
> occasionally, I find in my client logs a conflict error on a OOBucket
> instance stored as _change_buffer in Catalog persistent instances. The
> interesting part is that the Catalog has the following code as part of
> its __setstate__ method:
>
> def __setstate__(self, state):
> # Load the _change_buffer to ensure we have its state and avoid
> # a ReadConflictError when handling it
> list(self._change_buffer.items())
I don't understand: when did self._change_buffer get loaded? Isn't that
the responsibility of this __setstate__ method? Did you omit crucial parts
of this __setstate__ implementation?
> which should AFAIK load all the _change_buffer items and therefore avoid
> any potential conflict there.
>
> What's dogging me is that __setstate__ *itself* is generating RCEs, and
> this is something I don't understand. Shouldn't we be inherently
> protected from RCEs when __setstate__ is called, given that we're at a
> transaction boundary already?
I don't think so, but I don't know why you believe you're at a transaction
boundary. __setstate__ gets called to materialize the state of a persistent
object, and loads routinely occur at times arbitrarily far removed from the
most recent transaction boundary. In the absence of MVCC, RCE is expected
if an object O has been modified between the time the current transaction
began and the time O.__setstate__() is called. For example,
1. a transaction ends
2. a new transaction (implicitly) begins then
3. someone else modifies an OOBucket (commits a change to it)
4. this transaction tries to do O.__setstate__, where O._change_buffer
is the OOBucket someone else modified above
5. ReadConflictError is expected then: in the absence of MVCC, ZODB
won't let you load state that was modified since the transaction began
Any amount of time can pass between #2 and #3, and between #3 and #4. "The
transaction boundary" is the instant between #1 and #2.
More information about the ZODB-Dev
mailing list