Explicit two-phase commit (2PC)
===============================

..  Note::
   Two-phase commit isn't available with Quorum Commit, Group Commit, or CAMO. See  :ref:`Commit scope limitations <Overview of durability options>`  .

.. ::
   An application can explicitly opt to use two-phase commit with PGD. See `Distributed Transaction Processing: The XA Specification <http://pubs.opengroup.org/onlinepubs/009680699/toc.pdf>`_  .

The X/Open Distributed Transaction Processing (DTP) model envisions
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

PGD supports explicit external 2PC using the ``PREPARE TRANSACTION`` and
``COMMIT PREPARED`` /``ROLLBACK PREPARED`` commands. Externally, an 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 are replicated, and PGD
then applies post-commit conflict resolution.

Using ``bdr.commit_scope`` set to ``local`` might not seem to make sense
with explicit two-phase commit. However, the option is offered to allow
you to control the tradeoff between transaction latency and robustness.

Explicit two-phase commit doesn’t work with Quorum Commit, Group Commit,
or CAMO, as those commit scope kinds use two-phase commit internally.
Explicit two-phase commit also doesn’t work well with :ref:`Parallel Apply <Parallel Apply>`  or
:ref:`Using with transaction streaming <Using with transaction streaming>`  . Disable both before using explicit two-phase commit.

Use
---

Two-phase commits with a local commit scope work exactly like standard
PostgreSQL. Use the local commit scope:

.. code:: sql

   BEGIN;
   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:

.. code:: sql

   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:

.. code:: sql

   COMMIT PREPARED some-global-id;
