postgresqltwo-phase-commit

Using two phase commits on Postgres


Assuming that a have a table called "t1" in a "db1" and other table called "t2" in a "db2", and I need to insert a record on both tables or fails.

Connected to db1, I guess I shall type this:

BEGIN;
PREPARE TRANSACTION 'pepe'; -- this says the manual that makes your transaction gets stored on disk, so what is the purpose if I can't use it from another database?)

insert into t1 (field) values ('a_value');

COMMIT PREPARED 'pepe'

Connected to db2, I guess that:

BEGIN;
PREPARE TRANSACTION 'pepe'; -- this fails (the name of the transaction, what is the meaning, what is use for?)
 -- It complains about this "ERROR:  transaction identifier "pepe" is already in use"

insert into t2 (field) values ('another_value');

COMMIT PREPARED 'pepe'

As you may see I don't understand how to use two phase commits on Postgres.

Summary

I'm not getting how to perform synchronization commands on different DB within the same RDBMS.

I have read in the Postgres documentation that for synchronizing works across two or more unrelated Postgres databases an implementation of the so called "two-phases commits" protocol is at our disposal.

So I start trying to see how people do actually use them within the Postgres, I do not see any actual example, at most I get to this post of a guy that was trying to experiment with several Postgres client connected to the different databases in order to emulate the multiple process running in paralell doing things to the several dbs that should end in a successful (all commit) or failure result (all rollback).

Other sources I have seen examples were:

Resolution (After Laurenz's Answer)

Connected to db1, these are the SQL lines to execute:

BEGIN;
-- DO THINGS TO BE DONE IN A ALL OR NOTHING FASHION
-- Stop point --    
PREPARE TRANSACTION 't1';
COMMIT PREPARED 't1' || ROLLBACK PREPARED 't1' (decision requires awareness and coordination)

Meanwhile connected to the db2 these will be the script to execute:

BEGIN;
-- DO THINGS TO BE DONE IN A ALL OR NOTHING FASHION
-- Stop point --  
PREPARE TRANSACTION 't2';

COMMIT PREPARED 't2' || ROLLBACK PREPARED 't2'

Solution

  • I think you misunderstood PREPARE TRANSACTION.

    That statement ends work on the transaction, that is, it should be issued after all the work is done. The idea is that PREPARE TRANSACTION does everything that could potentially fail during a commit except for the commit itself. That is to guarantee that a subsequent COMMIT PREPARED cannot fail.

    The idea is that processing is as follows:

    That way, you can guarantee “all or nothing” across several databases.

    One important component here that I haven't mentioned is the distributed transaction manager. It is a piece of software that persistently memorizes where in the above algorithm processing currently is so that it can clean up or continue committing after a crash.

    Without a distributed transaction manager, two-phase commit is not worth a lot, and it is actually dangerous: if transactions get stuck in the “prepared” phase but are not committed yet, they will continue to hold locks and (in the case of PostgreSQL) block autovacuum work even through server restarts, as such transactions must needs be persistent.

    This is difficult to get right.