OxiDB implements full ACID transactions using Optimistic Concurrency Control (OCC) with a 3-phase commit protocol. This provides strong consistency guarantees while maintaining high performance for read-heavy workloads.
What is ACID?
- Atomicity — all operations in a transaction succeed or all fail together
- Consistency — the database moves from one valid state to another
- Isolation — concurrent transactions don't interfere with each other
- Durability — committed transactions survive crashes (WAL with 3-fsync protocol)
Using Transactions
from oxidb import OxiDbClient
db = OxiDbClient("127.0.0.1", 4444)
# Transfer money between accounts
with db.transaction() as tx:
alice = tx.find_one("accounts", {"user": "alice"})
bob = tx.find_one("accounts", {"user": "bob"})
tx.update_one("accounts", {"user": "alice"}, {
"$set": {"balance": alice["balance"] - 100}
})
tx.update_one("accounts", {"user": "bob"}, {
"$set": {"balance": bob["balance"] + 100}
})
# Both updates commit atomically
# If anything fails, both are rolled back
How OCC Works
OxiDB uses Optimistic Concurrency Control, which works in three phases:
- Begin — start a transaction and get a snapshot. All reads see a consistent view of the data.
- Read/Write — perform operations normally. All writes are buffered in memory and not yet applied to the actual data.
- Commit — validate that no other transaction has modified the same documents since we read them (version check). If valid, write WAL entries and apply changes. If conflict detected, abort and return an error.
Version Map & Conflict Detection
Each document has a version counter. When a transaction reads a document, it records the version. At commit time, it checks that versions haven't changed:
# Two concurrent transactions modifying the same document:
# Transaction A reads document (version 5)
# Transaction B reads document (version 5)
# Transaction A commits — document becomes version 6 ✓
# Transaction B tries to commit — sees version 6 ≠ 5 → CONFLICT!
On conflict, the transaction is aborted and your application can retry:
from oxidb import TransactionConflictError
retries = 3
for attempt in range(retries):
try:
with db.transaction() as tx:
# ... your operations ...
pass
break # success
except TransactionConflictError:
if attempt == retries - 1:
raise # give up after max retries
continue # retry
Deadlock Prevention
OxiDB prevents deadlocks by acquiring collection locks in sorted order (using a BTreeSet of collection names). This ensures that if Transaction A and Transaction B both need collections "orders" and "users", they always lock them in alphabetical order, eliminating circular wait conditions.
WAL & Durability
The Write-Ahead Log ensures durability with a 3-fsync protocol:
- Write WAL entry with CRC32 checksum → fsync
- Apply changes to data files → fsync
- Write checkpoint → fsync
On crash recovery, OxiDB replays uncommitted WAL entries and rolls back incomplete transactions.
Discussion 0
No comments yet. Start the conversation.