transaction support for ordering transactions.
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? Anthony Patch against current-cvs follows: --- lib/python/ZODB/Transaction.py 2000/05/30 19:03:27 1.22 +++ lib/python/ZODB/Transaction.py 2000/06/06 04:01:51 @@ -117,6 +117,9 @@ for c in self._connections.values(): c.close() del self._connections + def _prepend(self, object): + self._objects = [object] + self._objects + def sub(self): # Create a manually managed subtransaction for internal use r=self.__class__() @@ -315,9 +318,12 @@ del objects[:] # clear registered if not subtransaction and self._id is not None: free_transaction() - def register(self,object): + def register(self,object,early=0): 'Register the given object for transaction control.' - self._append(object) + if early: + self._prepend(object) + else: + self._append(object) def note(self, text): if self.description: -- Anthony Baxter <anthony@interlink.com.au> It's never too late to have a happy childhood.
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.
participants (2)
-
Anthony Baxter -
Phillip J. Eby