mongodb/mongo
Transactions
MongoDB supports multi-document, multi-statement, and (since 4.2) multi-shard ACID transactions. The data side is in src/mongo/db/transaction/ plus per-session state in src/mongo/db/session/. The router-side coordinator is the TransactionRouter in src/mongo/s/transaction_router.cpp.
Purpose
Transactions provide:
- Atomicity across multiple documents and (with sharded transactions) multiple shards.
- Snapshot isolation — reads see a consistent snapshot at a single cluster timestamp.
- Retryable writes — a related but distinct mechanism that retries individual statements safely.
Single-shard transaction
sequenceDiagram
autonumber
participant Client
participant Mongod
participant TxnP as TransactionParticipant
participant Storage
Client->>Mongod: stmt 1 (txnNumber=N, autocommit=false, startTransaction=true)
Mongod->>TxnP: beginOrContinue(N)
TxnP->>Storage: open snapshot
Storage-->>TxnP: snapshot at TS_N
Mongod->>Mongod: run stmt 1 in WUOW
Mongod-->>Client: ack
Client->>Mongod: stmt 2 (txnNumber=N)
Mongod->>TxnP: continue(N)
Mongod->>Mongod: run stmt 2 in WUOW
Mongod-->>Client: ack
Client->>Mongod: commitTransaction
Mongod->>TxnP: commit
TxnP->>Storage: commit WUOW (single oplog entry with applyOps)
Storage-->>TxnP: ok
TxnP-->>Mongod: ok
Mongod-->>Client: okEach transaction is identified by (lsid, txnNumber). The TransactionParticipant holds the per-session state, including the open WriteUnitOfWork and storage snapshot. On commit, the writes are batched into a single applyOps oplog entry so secondaries apply them atomically.
Multi-shard (cluster) transaction
When a transaction touches more than one shard, mongos orchestrates a cooperative two-phase commit:
graph TD
Client -->|stmts| Router[TransactionRouter on mongos]
Router -->|targeted stmts| ShardA
Router -->|targeted stmts| ShardB
Router -->|targeted stmts| ShardC
Client -->|commit| Router
Router -->|coordinate at ShardA| Coord[TransactionCoordinator on ShardA]
Coord -->|prepare| ShardA
Coord -->|prepare| ShardB
Coord -->|prepare| ShardC
ShardA -->|prepareTimestamp| Coord
ShardB -->|prepareTimestamp| Coord
ShardC -->|prepareTimestamp| Coord
Coord -->|commitTimestamp = max(prepareTs)| ShardA
Coord -->|commitTimestamp| ShardB
Coord -->|commitTimestamp| ShardCSteps:
- The router picks the at-cluster-time read snapshot — typically the cluster majority commit point.
- Each statement is routed to one or more shards with the snapshot pinned and
autocommit=false. - On commit, the router elects a coordinator (one of the participating shards) and sends
coordinateCommitTransaction. - The coordinator runs two-phase commit: send
prepareTransactionto every participant, gather prepare timestamps, choosecommitTimestamp = max(prepareTimestamp), and sendcommitTransactionto every participant. - If any participant returns an error during prepare, the coordinator sends
abortTransactionto all.
The router's state machine and the participants' prepare/commit logic together make up MongoDB's most intricate distributed protocol. The router-side implementation is in transaction_router.cpp (3.7 k lines) and tested in 13 k lines); the data-side coordinator is in transaction_router_test.cpp (src/mongo/db/global_catalog/sharding_environment/transaction_coordinator*.cpp.
Read concerns and snapshots
Transactions use:
readConcern: "snapshot"— every read sees a single cluster-wide timestamp.readConcern: "majority"— single-shard transactions can run with majority too, snapshotting at the local majority commit point.
The chosen snapshot is propagated as atClusterTime to every participating shard so that all reads, even cross-shard, observe the same view.
Retryable writes
Distinct from transactions, retryable writes let drivers safely retry single statements after a network or primary-failover error. The server stores a per-stmtId record in the session catalog so that a retry returns the same response without re-executing the write. Source: src/mongo/db/session/session_txn_record_*.cpp and the TransactionParticipant.
Internal transactions
Some server-side code (e.g. the resharding coordinator, the findAndModify upsert path) needs to run multi-statement transactions internally without a client lsid. The internal transactions framework (src/mongo/db/transaction/internal_transactions_feature_flag.idl and surrounding) provides synthetic session ids to scope these.
Session catalog
The session catalog (src/mongo/db/session/) tracks per-lsid state across sessions, transactions, retryable writes, and migrations:
SessionCatalog— global registry of(lsid, txnNumber)participants.OperationSessionInfo— the per-request session metadata extracted from the command.- The
config.transactionscollection persists session state across primary failover.
Failure handling
- Primary failover during a transaction — the new primary recovers the session catalog from
config.transactions. Prepared transactions are resumed; in-progress un-prepared transactions are aborted. - Network errors during commit — the coordinator persists its decision before responding, so the router can retry
coordinateCommitTransactionand get the same answer. - Stale shard versions — the router refreshes its routing cache and, depending on the protocol phase, may either retry the affected statement or abort the transaction.
Key source files
| File | Purpose |
|---|---|
src/mongo/db/transaction/transaction_participant.cpp |
Per-session participant on mongod. |
src/mongo/db/transaction/transaction_history_iterator.cpp |
Walks the oplog entries belonging to a transaction. |
src/mongo/db/session/ |
Session catalog and per-session state. |
src/mongo/s/transaction_router.cpp |
Cluster transaction state machine on mongos. |
src/mongo/db/global_catalog/sharding_environment/ |
TransactionCoordinator on the elected shard. |
src/mongo/db/transaction_validation.cpp |
Cross-cutting transaction validation rules. |
Integration points
- Replication — multi-statement transactions are persisted as
applyOpsoplog entries. - Sharding — every cluster transaction goes through the router and the catalog cache.
- Op observer — emits prepare/commit/abort oplog entries.
- Storage — provides the snapshot, prepared transaction support, and the timestamping primitives.
- Change streams — see committed transactions as a single batch in their event stream.
Entry points for modification
Most transaction-related work touches the participant or the router. Adding a new error to the cluster transaction protocol means updating transaction_router.cpp, the participant, and the (very large) router test file. Changes to retryable writes are scoped to the session catalog. New cross-cutting validation goes in transaction_validation.cpp. The multi_statement_transaction* resmoke suites and the jstests/replsets/ and jstests/sharding/ transactions tests are the primary safety nets.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.