[ZODB-Dev] [zopefoundation/ZODB] 49919d: test for POSKeyError during transaction commit
Godefroid Chapelle
gotcha at bubblenet.be
Wed Feb 5 15:23:13 CET 2014
Le 05/02/14 13:25, Jim Fulton a écrit :
>>>> Acquisition is added as a test dependency. Any hint how to replicate
>>>> >> >the bug without acquisition is welcome.
>>> >>
>>> >>Define a subclass of Persistent which emulates what Acquisition does, e.g.:
>>> >>
>>> >> from persistent import Persistent
>>> >> class Foo(Persistent):
>>> >> @property
>>> >> def _p_jar(self): # or whatever attribute trggers
>>> >> return object()
>> >
>> >What if full replication requires a C extension module?
>> >
>> >(I hope that's not true and that it is possible to reproduce the bug
>> >using some fakes, but I haven't spent the time investigating this.)
> I'm going to dig into this. I'm baffled by the assertion that this has
> anything to do with readCurrent.
For sure : the POSKeyError happens during connection.commit when
checking oids stored in Connection._readCurrent mapping.
(see traceback at http://rpatterson.net/blog/poskeyerror-during-commit)
The _readCurrent mapping is populated only by calls to
Connection.readCurrent method.
In the Plone code base, the only way I found to get that
Connection.readCurrent method to be called is by adding a key value pair
to a BTree.
_BTree_set C function is then called, which in turn calls readCurrent by
inlining the PER_READCURRENT macro.
This calls the cPersistence.c readCurrent function, which in turn calls
readCurrent method on the ZODB connection.
When setting a key value pair on a new (not already committed) instance
of a standard BTree, readCurrent method is not called on the connection.
My understanding is that it is due to the fact that _p_jar and _p_oid
are only set during transaction commit.
However, with a new BTree instance that also inherits from
Acquisition.Implicit, readCurrent method is called on ZODB connection
when setting key value pair. The only explanation I found is that this
instance _p_jar attribute has a value (acquired in a way or another ?).
In this case, when readCurrent is called on an object created during a
savepoint and this savepoint is rolled back, the oid is leftover in the
Connection._readCurrent mapping. This leads to the POSKeyError when
committing later as checkCurrentSerialInTransaction cannot check the
object since it went away at rollback.
This brings us to the fix I propose: calls to readCurrent should not
track objects with oid equal to z64.
AFAICS, this is inline with readCurrent API goal which is (if I
understand well) to ensure that an object manipulated by two connections
does not get into an incoherent state.
An object that has never been committed cannot be accessed by a second
transaction hence does not need to participate in readCurrent dance.
This was a very long explanation which I hope will help to confirm the
fix or to come up with a better one.
PS: keep in mind that english is not my mothertongue.
--
Godefroid Chapelle (aka __gotcha) http://bubblenet.be
More information about the ZODB-Dev
mailing list