Important

Helios features are now enabled during weekly update windows and are no longer directly tied to SingleStore engine releases. Refer to the release notes to view the latest features available in your Helios cluster.

Two-Phase Transaction Commit

SingleStore supports atomic, distributed transactions. Two-phase commit (2PC) is used in conjunction with locking to ensure data consistency across nodes in distributed transactions. Refer to BEGIN for more information about using transactions in SingleStore.

The 2PC Protocol

The 2PC protocol ensures that all changes in a transaction are either committed or rolled back. Transactions in distributed database systems such as SingleStore modify data on multiple nodes. To maintain the integrity of a transaction, the database must ensure that one of the following two things happens:

  • The transaction commits: All of the transaction's updates on all involved nodes are completed.

  • The transaction rolls back: None of the updates are completed.

The 2PC protocol coordinates among the nodes to ensure this all-or-nothing behavior, also called transaction atomicity, is enforced.

2PC Workflow

In 2PC, a node is designated as the coordinator and is responsible for coordinating transaction commits across other participating nodes. In SingleStore, the coordinator role is performed by the aggregator node(s).

The 2PC protocol operates in two phases, a prepare phase and a commit phase.

Prepare Phase

In the prepare phase, the coordinator (the aggregator handling the transaction) contacts participating nodes and sends a prepare request to all the participants in parallel. The coordinator orchestrates the transaction’s operations on the participating nodes before the transaction is finalized. Each participant node executes the statements for its local partition transaction, and then responds with a vote indicating whether it is (or is not) OK to commit.

If one or more nodes have indicated that they cannot commit by voting NO, the coordinator sends rollback requests to all the nodes to roll back the entire transaction.

Commit Phase

Once all the votes are received, if all nodes have indicated they are OK to commit, the coordinator sends out commit requests. Each node commits the transaction locally and sends an acknowledgement (ack) back to the coordinator to indicate their local commit is complete. Once the coordinator has received and recorded all the ack votes, the transaction is considered committed from the perspective of transaction atomicity. If a node crashes or the connection between nodes is lost after this point, recovery behavior depends on the database’s durability and replication settings. The logging process on all the nodes ensures that all changes in the transaction are still recorded.

Two-phase commit guarantees an all-or-nothing commit decision across participating nodes, but survival of an acknowledged commit after a crash is a separate durability question. With ASYNC DURABILITY, a node can acknowledge COMMIT before its log records are hardened to disk. If that node or host crashes before hardening completes, recently acknowledged transactions on the node can be lost.

Note

When all participants have prepared successfully, the transaction’s final outcome is a commit; a later coordinator/leaf failure does not change the final outcome to rollback.

If the coordinator backs off or fails, the participants can use the 2PC resolution protocol to determine the outcome and complete the transaction during recovery. If a leaf that holds a prepared transaction crashes, the transaction is recovered in the prepared state after crash recovery. In effect, participant nodes can take over the coordinator's role for resolution.

In high-availability (HA) deployments, if a data node (leaf) dies during a distributed transaction, an HA cluster can often still finish deciding the transaction without waiting for that exact node to come back online.

2PC Example

Consider a songs table and the following query. Assume that there are millions of rows in the songs table which are distributed across many nodes.

CREATE TABLE songs(Id INT,
Name TEXT,
Genre TEXT,
Rating DOUBLE,
PublishTimestamp DATETIME);
UPDATE songs
SET Genre = 'Pop' WHERE Genre = 'Pop Music';

This query updates all the rows in the songs table that have Genre = 'Pop Music' to Genre = 'Pop'. As the rows that need to be updated are distributed across multiple nodes, this update also involves multiple nodes. Because this query runs as a transaction, this update must be atomic (all-or-nothing); either every row with Genre='Pop Music' is updated, or none are. This is called atomicity, one of the ACID properties of transactions, and 2PC helps guarantee it.

The following figure illustrates 2PC for the songs table when the affected rows are distributed across two nodes. The coordinator first sends prepare requests to both the nodes. The nodes then vote either YES or NO. When both the nodes vote YES, then commit requests are sent to both nodes. The nodes commit the transactions locally, and respond with an ack to the coordinator. The commit phase completes when all participating nodes have committed their local transactions and acknowledged the outcome. If any node votes NO, the rollback phase completes when all participating nodes have rolled back their local transactions and acknowledged the outcome.

Two phase Transaction Commit page

In SingleStore, the coordinator role is performed by the aggregator and Node 1, Node 2 are leaf nodes.

All queries such as the preceding are run in transactions. The BEGIN, COMMIT, and ROLLBACK statements can be used to run multi-statement transactions, i.e., run multiple updates within a transaction. The same 2PC process is used for those transactions.

The discussion and behavior apply to all data updates including INSERT and DELETE DML commands.

Troubleshooting 2PC

When a distributed transaction enters 2PC, an interrupt or failure can prevent SingleStore from returning a confirmed final result to the client. For example, a kill query request, client disconnection, or another failure that interrupts processing or commit decisions. In this case, the query may end up in an unknown state and return the following error:

OperationalError: 1997: Attempted to interrupt transaction execution, but the outcome is unknown because the transaction was already in its commit phase. Please check if it succeeded.

This error message means that the transaction outcome is unknown from the client's perspective. It does not mean that SingleStore partially applied the transaction or the database is in an inconsistent state. The transaction still resolves atomically; it is either fully committed or fully rolled back. If all participants prepared successfully, the final outcome is a commit. Otherwise, the final outcome is a rollback.

Therefore, when Error 1997 is returned, verify the final result in the affected data before retrying application logic.

2PC Impacts

The 2PC feature is enabled by default on all SingleStore 8.5 and later and has a negligible performance impact.

Last modified:

Was this article helpful?

Verification instructions

Note: You must install cosign to verify the authenticity of the SingleStore file.

Use the following steps to verify the authenticity of singlestoredb-server, singlestoredb-toolbox, singlestoredb-studio, and singlestore-client SingleStore files that have been downloaded.

You may perform the following steps on any computer that can run cosign, such as the main deployment host of the cluster.

  1. (Optional) Run the following command to view the associated signature files.

    curl undefined
  2. Download the signature file from the SingleStore release server.

    • Option 1: Click the Download Signature button next to the SingleStore file.

    • Option 2: Copy and paste the following URL into the address bar of your browser and save the signature file.

    • Option 3: Run the following command to download the signature file.

      curl -O undefined
  3. After the signature file has been downloaded, run the following command to verify the authenticity of the SingleStore file.

    echo -n undefined |
    cosign verify-blob --certificate-oidc-issuer https://oidc.eks.us-east-1.amazonaws.com/id/CCDCDBA1379A5596AB5B2E46DCA385BC \
    --certificate-identity https://kubernetes.io/namespaces/freya-production/serviceaccounts/job-worker \
    --bundle undefined \
    --new-bundle-format -
    Verified OK

Try Out This Notebook to See What’s Possible in SingleStore

Get access to other groundbreaking datasets and engage with our community for expert advice.