[ZODB-Dev] ZODB4 project plan

Shane Hathaway shane@zope.com
Fri, 29 Nov 2002 15:19:44 -0500 (EST)


On Fri, 29 Nov 2002, Christian Reis wrote:

> On Fri, Nov 29, 2002 at 12:41:37PM -0500, Shane Hathaway wrote:
> > You would also want to decouple transactions from threads, which isn't
> > very hard, especially since there's now a Connection.register() method
> > which you can override to choose the correct transaction.  I won't
> > ramble on about this unless you tell me I'm on the right track, though. :-)
>
> Can we do this today easily in ZODB3?

I believe so.  The only tough requirement is that you abandon the
convenient get_transaction() function.  Because it accepts no arguments,
it cannot possibly know which transaction to use unless transactions are
bound to threads.  Instead, you must get the transaction from the
connection.  I would start by subclassing Connection like this (untested):


class TransactionalConnection (Connection):

    _transaction = None

    def getTransaction(self):
        """Gets or creates a transaction for this connection."""
        t = self._transaction
        if t is None:
            t = Transaction()
            self._transaction = t
        return t

    def register(self, object):
        """Register an object with the transaction."""
        assert object._p_jar is self
        self.getTransaction().register(object)


Note that the only change to register() is to use self.getTransaction()
instead of get_transaction().  Transaction objects are reusable, so you
probably don't have to get rid of the _transaction attribute at
tpc_finish()/tpc_abort() time.  But you'll have to override every method
of Connection that uses get_transaction(), changing it to call
self.getTransaction().

Hmm.  Now that I wrote that, it occurs to me that Connection ought to have
a getTransaction() method anyway, where the default would call
get_transaction().  The performance penalty would be minimal.  Projects
like yours would be easier to accomplish.

The only other code in ZODB that relies on the get_transaction() builtin
is the ExportImport class, which is a base class of Connection.  The
dependency is shallow.  So once both Connection and ExportImport use the
getTransaction() method, and you override the getTransaction() method, I
think transactions and threads will be fully decoupled in ZODB.  You'll
just have to change your app to use ob._p_jar.getTransaction() instead of
get_transaction().

I think we should do this for ZODB 3.2.  Maybe we should even provide some
mechanism that makes it unnecessary for you and others to subclass
Connection.

Kapil's patch tries to achieve close to the same thing, but without losing
get_transaction().  It looks like a good piece of work, but it's a monkey
patch that's probably not compatible with the latest changes to ZODB.
I'm not sure we really need to keep get_transaction(), but if we want it,
we could say that when transactions are decoupled from threads,
get_transaction() now requires a connection or an object from a connection
as an argument.  So instead of this code:

  ob.writeme = 1
  get_transaction().commit()

You'd write this:

  ob.writeme = 1
  get_transaction(ob).commit()

Then, the implementation of get_transaction() would just call
ob._p_jar.getTransaction().

Shane