Explicit Two-Phase Commit (2PC) v3.7

An application may opt to use two-phase commit explicitly with BDR. See Distributed Transaction Processing: The XA Specification.

The X/Open Distributed Transaction Processing (DTP) model envisages three software components:

  • An application program (AP) that defines transaction boundaries and specifies actions that constitute a transaction.
  • Resource managers (RMs, such as databases or file access systems) that provide access to shared resources.
  • A separate component called a transaction manager (TM) that assigns identifiers to transactions, monitors their progress, and takes responsibility for transaction completion and for failure recovery.

BDR supports explicit external 2PC using the PREPARE TRANSACTION and COMMIT PREPARED/ROLLBACK PREPARED commands. Externally, a EDB Postgres Distributed cluster appears to be a single Resource Manager to the Transaction Manager for a single session.

When bdr.commit_scope is local, the transaction is prepared only on the local node. Once committed, changes will be replicated, and BDR then applies post-commit conflict resolution.

Using bdr.commit_scope set to local may seem nonsensical with explicit two-phase commit, but the option is offered to allow the user to control the trade-off between transaction latency and robustness.

Explicit two-phase commit does not work in combination with either CAMO or the global commit scope. Future releases may enable this combination.

Usage

Two-phase commits with a local commit scope work exactly like standard PostgreSQL. Please use the local commit scope and disable CAMO.

BEGIN;

SET LOCAL bdr.enable_camo = 'off';
SET LOCAL bdr.commit_scope = 'local';

... other commands possible...

To start the first phase of the commit, the client must assign a global transaction id, which can be any unique string identifying the transaction:

PREPARE TRANSACTION 'some-global-id';

After a successful first phase, all nodes have applied the changes and are prepared for committing the transaction. The client must then invoke the second phase from the same node:

COMMIT PREPARED 'some-global-id';