ACID Transactions

Multi-collection transactions with optimistic concurrency control.

# Python example
tx = db.begin_transaction()

db.tx_insert(tx, "accounts", {"id": "A", "balance": 1000})
db.tx_update(tx, "accounts", {"id": "B"}, {"$inc": {"balance": -500}})
db.tx_update(tx, "accounts", {"id": "A"}, {"$inc": {"balance": 500}})

db.commit_transaction(tx)  # atomic commit or rollback on conflict

How It Works

  • Optimistic Concurrency Control (OCC) -- Writes are buffered until commit. No locks held during the transaction.
  • Per-document versioning -- Each document has a version counter. Commit validates that no versions changed since read.
  • 3-phase commit -- Prepare, validate versions, commit. WAL entries tagged with transaction IDs.
  • Deadlock-free -- Collections are locked in sorted order (BTreeSet) during commit.
  • Crash recovery -- Transaction log with CRC32 checksums. WAL replay on startup.

Transaction API

MethodDescription
begin_transaction()Start a new transaction, returns transaction ID
tx_insert(tx, col, doc)Buffered insert
tx_find(tx, col, query)Read from committed state (does NOT see same-tx buffered writes — OCC semantics)
tx_update(tx, col, query, update)Buffered update
tx_delete(tx, col, query)Buffered delete
commit_transaction(tx)Validate and commit atomically
rollback_transaction(tx)Discard all buffered changes

Transactions in cluster mode v0.25.x

When the server runs with --features cluster behind oxipool, transactions are pinned to a single shard for their entire lifetime:

  • begin_tx grabs a backend connection from the targeted shard's master pool and locks it to that client until commit_tx or rollback_tx.
  • Every operation inside the transaction must route to the same shard. Cross-shard writes inside a tx are rejected with cross-shard transactions not supported; use the same shard key within a transaction.
  • On commit, the buffered writes are applied as a single Raft log entry (OxiDbRequest::CommitTransaction), replicated to all followers in the shard's Raft group, and ack'd to the client.
  • OCC's version-conflict detection still applies within the shard — concurrent transactions touching the same documents in that shard will conflict normally.

Practical consequence: pick a shard key your tx data shares (e.g. customer_id for a checkout flow), and the cluster gives you the same atomicity story as standalone mode.