ACID on a single primary
On one primary a graph store gives full ACID by writing changes to a durable write-ahead logical log before commit and holding write locks until commit (detecting deadlocks with a wait-for graph), which is correct and simple but caps write throughput at a single machine — the reason distribution becomes tempting.
A lock was just one ingredient; the full promise is ACID — a logical log that survives crashes, write locks held to commit, deadlock detection on a wait-for graph. One primary gives you all of it, cleanly. The catch is in 'one primary': every write funnels through a single machine. To go bigger, we have to split the graph — and that's where everything we've built starts to hurt.
Scene 10
ACID on a single primary
- Watch
- Try it
- Predict
- Capture
Watch one transaction. Alice follows Bob and Carol — two relationship inserts that must commit together. Before T1 touches the store, it appends each change to a write-ahead log and takes a write lock on the node it mutates. Then the power fails MID-commit — the COMMIT marker never reaches disk. On restart, recovery replays only the entries that were made durable, so the half-finished write simply vanishes and the graph is back to a consistent state. The change either fully happened or it didn't.
Highlighted lines are the ones running in the diagram right now.
def commit(txn):for change in txn.changes: # the multi-edge writelog.append(change) # write-ahead: log firstlog.fsync() # make the changes durablelog.append(COMMIT, txn.id) # the commit markerlog.fsync() # durable commit = it survivesapply_to_store(txn.changes) # only now touch the storerelease_locks(txn) # held until commit
def acquire_write(txn, node):while node.write_lock.held_by_other(txn):txn.wait_for(node.write_lock.owner) # edge in wait-for graphblock_until_freed_or_aborted() # may be the deadlock victimnode.write_lock.grant(txn) # exclusive: no interleavingtxn.held_locks.add(node) # held until commit/abort
Where this sits in Build a graph database (Neo4j / Dgraph-style)
Scene 10 of 16, in the Scale & ACID act — ACID on one box; the partition cut turns hops to RPCs.. A single-primary graph store gives full ACID — a write-ahead logical log for durability, write locks held to commit, and deadlock detection via a wait-for graph — at the cost of write throughput bounded by one machine.
Up next. ACID on one machine is clean because every pointer lives in the same address space. The moment the graph outgrows one box and we split it, the value of a graph IS the edges between keys — so any cut we make will sever edges, and a hop across the cut stops being a pointer dereference and becomes a network round trip. You cannot shard a graph the way you shard a key-value store.
All 16 scenes in Build a graph database (Neo4j / Dgraph-style) · Every curriculum