[DB-SIG] Two-phase commit API proposal (was Re: Any standard for two phase commit APIs?)

James Henstridge james at jamesh.id.au
Mon Jan 21 12:31:38 CET 2008


On 21/01/2008, M.-A. Lemburg <mal at egenix.com> wrote:
> On 2008-01-21 11:28, Federico Di Gregorio wrote:
> > I agree with your analisys, I'll add some comments about the proposal
> > below.
> >
> > Il giorno lun, 21/01/2008 alle 19.08 +0900, James Henstridge ha scritto:
> >>  1. Add a Connection.begin(...) method that explicitly starts a
> >>     transaction.  Some argument (possibly the transaction ID) causes
> >>     the transaction to use two-phase commit.  May raise
> >>     NotSupportedError if two-phase commit is not supported.
> >
> > DBAPI always had implicit transaction begin (for backends supporting
> > transactions) and adding an explicit begin() method would just add
> > confusion onto the user. "Should I always call begin()? Or just when I
> > want to start a two-phase?". I'd better like the two-phase begin method
> > named otherwise. Let's call it xa_begin() in this discussion.
>
> Agreed.
>
> I also think that we should prepend all of these methods with
> "xa_" or something similar: database backends may need to be to
> differentiate whether the user wants to e.g. commit in the context
> of a two-phase commit transaction or a regular one and the two-phase
> commit is also likely going to require an argument (the transaction id).
>
> Using a different set of methods would also make it clear to
> the reader of the code, that a two-phase commit transaction is
> happening (which does work a lot different from a one-phase one).

I'm indifferent about this.  I don't think using the same
commit/rollback methods presents much confusion.


> >>  2. Add a Connection.prepare() method that peforms the first stage of
> >>     two-phase commit.  May raise NotSupportedError if two-phase commit
> >>     is not supported, or the transaction was not started in two-phase
> >>     mode.
> >>
> > Ok. (Should be named accordingly with the begin method.)
>
> xa_prepare(xid)

In what cases would you pass a different xid to xa_prepare() vs. what
was passed to xa_begin()?

If not, then I'd leave the argument out: I've already told the
connection what the transaction ID is once already.

> >>  3. Calling commit() or rollback() on the connection after prepare()
> >>     performs the second stage of the commit.
> >>
> > Ok.
>
> xa_commit(xid) and .xa_rollback(xid)

Having these arguments would be quite useful for the recovery use-case.

I think it'd be useful to be able to use the methods without an
argument to operate on the current transaction too though.

> >>  4. Calling commit() or rollback() on the connection prior to
> >>     prepare() performs a one-phase commit or rollback.
> >>
> > IMHO, it should raise an error if the transaction was started for
> > two-phase. Otherwise I don't see any reason for (1).
>
> Agreed. They should raise an error.
>
> In fact, when operating in two-phase commit mode, I think
> using the one-phase methods .commit() and .rollback() should
> raise an error. Mixing the two is normally not a good idea and
> may very well result in an undefined state.

If we have separate rollback vs. xa_rollback, then sure.  But some
rollback method should be allowed before preparing the transaction.
The same goes for committing.


> >>  5. Executing statements after prepare() but before commit() or
> >>     rollback() results in an error (ProgrammingError?)
> >>
> > Ok.
>
> Agreed.
>
> >>  6. Closing a connection with a prepared but uncommitted transaction
> >>     rolls back that transaction.
> >>
> > Stuart's comment on psycopg ML made me think about this one. Maybe we
> > want an option added to xa_begin() to keep the prepared transaction open
> > even if the connection drops.
>
> A connection drop should always trigger an implicit rollback on the
> server side, so I'm not sure how and where you'd keep the required
> state to continue processing the transaction in case the connection
> is reestablished.

Uncommitted prepared transactions survive the connection in PostgreSQL
and can be committed from another connection.

Many 2PC-supporting databases provide some way of listing existing
transactions (e.g. MySQL's "XA RECOVER" statement), so I doubt
PostgreSQL is unique here.

At a minimum it'd be helpful to emit a warning in this case.

James.


More information about the DB-SIG mailing list