[Zope-dev] transaction support for ordering transactions.

Phillip J. Eby pje@telecommunity.com
Tue, 06 Jun 2000 15:36:06 -0500


At 02:34 PM 6/6/00 +1000, Anthony Baxter wrote:
>  As part of making SQLSession transaction-sane, I'd like to be able
>to specify that something can register itself to be committed or
>aborted earlier in the list of objects rather than just being put on
>the end of the list. The reason for this: 
>
>  I want SQLSession to just use a normal DB connection, and have the
>commits &c to "just work". The new code now only does the SQL statements
>in SQLSessionObj's _finish() method - unfortunately, by that time, the
>database's '_finish()' method has sometimes already been called (if there's
>a different database call before the Session object is created, then the 
>database adaptor will be registered first).
>
>  I thought about various ways of dealing with this, such as being able
>to say 'register me _before_ that object', but ended up going simply with
>a flag to say 'put me on the front of the list, rather than the back.'
>
>  This way, anything that needs to say 'no, put me before the standard
>ones' can do so. 
>
>
>Thoughts? Alternatives?
>

Interesting.  I have a similar problem with triggers and index agents in
ZPatterns 0.4.0.  It would be solvable by the same general approach you've
presented (giving the transaction.register() method an option to register
for "early" commit).

There is an error in your patch, however. _prepend should use
self._objects.insert(0,object), as the way you're doing it now will break
the _append method.  (Because _append is a reference to _objects.append,
and you're replacing the old _objects with a new list.  Subsequent calls to
_append will append the object to the old _objects list, not the new one
you've just added.)  

There is also a *second* problem with your patch, which is more serious and
less correctable.  If a _prepend takes place *during* a commit operation,
the current implementation of the commit operation will be blown all to
hell, because it relies on knowing how far along it has gone in the
_objects list.  Instead of committing your newly prepended object, it will
re-commit the object it committed last, and if there's an error, the newly
prepended object will not be aborted.  Yuck.

Anyway...  I'm very much in favor of solving the same problem that you
are...  But it requires a rather more complex patch (so that
transaction.commit() could deal with prepends during commit) and first we'd
need to convince Jim that it's the right thing to do.  :)  (Not only that,
but he might come up with a better way to do it than prepending...)

Ironically, I'm not sure your problem actually *needs* this fix to be
solved.  You probably need to tie your session object's behavior to an
earlier transaction event (the "_p_jar.commit()" operation rather than
tpc_finish()), and you can then be guaranteed that the SQL connection has
not yet seen a tpc_finish() either.

*My* problem, on the other hand, is that even if I do this, ZODB does not
allow objects to be _p_jar.commit()ed twice; if you modify an object which
has already been _p_jar.commit()ed in the same transaction, you will get an
unresolvable ConflictError (because the ZODB thinks another transaction
modified the object before you).  Thus, I need to ensure that DataManagers
which are saving things up 'till a _p_jar.commit() operation, get
registered ahead of any modification to an object that they might need to
modify again later.  So a fully functional "prepend" capability would be of
great benefit to ZPatterns, but I'm not sure that your problem actually
needs it, and your patch, unfortunately, does not achieve it.