[Zope-dev] putting the 'two' back in tpc

Leonardo Rochael Almeida leo@hiper.com.br
04 Jun 2002 16:54:53 -0300


In a chat with Kapil at #zope we came to the conclusion that most Zope
database adaptors don't really implement two phase commit, because they
make no effort, during the 'vote' phase (the first phase of the tpc) to
make sure that the commit will go thru without errors. 

For example, if you have the following schema in postgresql: 

CREATE TABLE "passwd" ( 
        "username" character varying(64) UNIQUE, 
        "password" character varying(64) NOT NULL, 
        "roles" character varying(255), 
        Constraint "passwd_pkey" Primary Key ("username") 
); 

CREATE TABLE "userproperties" ( 
        "username" character varying(64) NOT NULL references "passwd"
(username) DEFERABLE INITIALLY DEFERRED, 
        "propname" character varying(128) NOT NULL, 
        "value" text NOT NULL, 
);

This schema allows an entry in the 'userproperties' table to exist
without an equivalent user in the 'passwd' table before the end of the
transaction.

If, on commit, there still isn't a user with the same 'username' on the
'passwd' column, postgres will raise an error and won't let the commit
go thru.

Now all the current DA implementations that I know of call the database
commit only in the second (or finish) phase of the tpc, which will
result in a locked down Zope, as Zope is not very much fond of people
bailing on him on the second phase.

Now the correct solution for this, as far as postgres is concerned, is
to execute the query, 'SET CONSTRAINTS ALL IMMEDIATE' in the 'vote'
phase, since no other query will be executed between this query and the
commit. Postgresql will raise an error while trying to execute this
query if any coinstraint is yet to be satisfied, so Zope will be able to
cancel the transaction to all those registered in the transaction
machinery. And if the postgresql documentation is correct, 'SET
CONSTRAINTS...' is an SQL92 and SQL99 standard, so other db's might be
able to benefit from this.

The problem is that lib/python/Shared/DC/ZRDB/TM.py doesn't provide a
_vote() slot which should be called by tpc_vote(). TM documentation
should mention that this slot should be overriden, just like _finish()
and _abort(). It should also mention why this slot should be overriden
("consistency this, consistency that, yadda yadda..").

The nazi bastard in me wants the default implementation of this slot to
raise an error to remind people to override it. If your DA doesn't need,
or can't, implement a _vote() for some reason, you should explicitly
override it to do nothing. However I know that breaking other people's
DA is not nice :-)

The not so nazi bastard in me says that the default _vote()
implementation should zLOG a warning about '_vote()' not being
implemented, but I know that even this might be too much to ask, since
logfiles everywhere would go crazy.

Anyway, this may be a little late, but I believe that implementing a
do-nothing _vote() that is called by TM.tpc_vote() is a small and
unintrusive change but a change that is important enough to deserve to
be included in 2.6, so that DA authors take notice and implement it
where possible.

I'd volunteer to make this change myself if my commiter's agreement had
been commited (I'm looking at you Paul Everitt). I know that I'll bug
the Psycopg guys once this change is thru.

Leo

-- 
Ideas don't stay in some minds very long because they don't like
solitary confinement.