shreyansh

Serial Execution and Achieving ACID

30-Second Glance

  • Serializable = the gold standard: concurrent txns behave exactly as if run in some serial order — no skew, no phantoms, no lost updates, period.
  • The blunt implementation is actual serial execution: one thread, no concurrency, transactions as stored procedures (VoltDB, Redis, early H-Store).
  • It works because OLTP txns are tiny (µs–ms) and partitionable: 1M+ TPS single-threaded is realistic when data fits the partition.
  • Fails for analytics, cross-partition txns (needs 2PC), and interactive multi-round-trip transactions — that's where SSI/2PL take over.

What "Serializable" Promises

Serializability is the strongest isolation level and the only one with a one-sentence definition: the effect of concurrent committed transactions is identical to running them one after another in some order. Every anomaly in the previous notes — dirty reads/writes, skew, lost update, write skew, phantoms — is impossible by construction. The app reasons single-threadedly; the DB absorbs all concurrency pain.

Three implementation families reach it, with very different bills:

Family Idea Systems Price
True serial execution One txn at a time per partition; no concurrency control needed VoltDB/H-Store, Redis (single-threaded commands), Datomic transactor Partition discipline; no interactive txns
Two-phase locking (2PL) Read/write + predicate locks held to commit; blocks conflicting txns InnoDB SERIALIZABLE, SQL Server, 2PL mode in many RDBMS Lock waits, deadlocks, contention collapse
Serializable snapshot isolation (SSI) Optimistic snapshot + abort on dangerous rw-patterns PostgreSQL SERIALIZABLE Abort/retry load, some false positives

2PL and SSI each get a full note (Two-Phase Locking, Serializable Snapshot Isolation). This note covers the serial-execution path and how the pieces compose into ACID end to end.

Serial Execution: Why It's Fast (and When It Isn't)

Throughput of a serial engine = 1 / (avg txn latency). If transactions are small stored procedures touching a single partition's RAM (typical OLTP: 50 µs–1 ms), one thread does 1K–20K TPS and a 24-partition box does 100K–1M+ TPS with zero lock manager, zero deadlock detector, zero MVCC version chains. VoltDB demonstrated this a decade ago; Redis's single-threaded command loop is the same idea for data structures.

Constraints that kill it:

  1. Partitionability. Single-partition txns are fast; multi-partition txns need 2PC across partitions (prepare/commit round trips + coordinator blocking risk), erasing the advantage. Design the schema so the hot paths are single-partition (user-id, order-id routing — see Partitioning).
  2. No interactive transactions. A txn that waits on the client (read → think → write) stalls the whole partition. Hence: stored procedures submitted whole, deterministic, no mid-txn I/O.
  3. No analytics. A 10-second scan holding the serial slot blocks 10K OLTP txns behind it. Real deployments split OLTP (serial) from OLAP (replica/columnar) — see Column-Oriented Storage.
  4. Replication lag discipline. Serial primary + async replicas = serial order preserved downstream; pair with Quorums or Raft for durability without breaking the serial story.

Achieving ACID End to End (Assembly Diagram)

Property Mechanism in a serial engine Mechanism in a concurrent engine
Atomicity Undo log per txn + abort on error/timeout; 2PC for multi-partition Same, plus deadlock-victim abort
Consistency Constraints checked at commit; app logic deterministic in sprocs Same; isolation level guards concurrent-invariant breaks
Isolation Serial order (free) 2PL locks / SSI dangerous-structure aborts / MVCC snapshots
Durability Command-log / WAL fsync or quorum before ACK; snapshot + replay on recovery Same (redo log, group commit, replicated log)

Durability numbers to quote: per-commit fsync on SSD ≈ 100 µs–1 ms → caps at ~1–10K TPS; group commit (batch N commits per fsync) or quorum-replicated log (Raft, 1 RTT ≈ 0.2–2 ms intra-AZ) restores 100K+ TPS with crash safety. Recovery = latest snapshot + replay of log tail; snapshotting every GBs of log keeps restart in minutes.

Trade-offs

Approach Pros Cons Use when
True serial execution Zero anomalies, simplest reasoning, no lock/SSI overhead, huge partitionable throughput Stored-procedure discipline; cross-partition 2PC; no ad-hoc analytics on primary Partitionable OLTP (billing, provisioning, game state, ledgers per entity)
2PL serializable General SQL, interactive txns, predicate locking Deadlocks, lock-wait latency, hot-row collapse General OLTP needing serializable without app rewrite
SSI serializable Optimistic — reads never block; good mixed workloads Abort storms under contention; false-positive aborts Postgres shops with mostly-low contention + strict invariants
Snapshot + constraints 90% of the benefit at 10% of the cost Residual predicate anomalies When every invariant is constraint-expressible

Interview One-Liners

  • Q: What does serializable guarantee that snapshot isolation doesn't? A: Equivalence to some serial order — which additionally rules out write skew and phantoms, the two predicate anomalies snapshots allow.
  • Q: Why can single-threaded execution beat concurrent engines? A: No locks, latches, deadlock detection, or version chains; at 100 µs/txn one thread already does 10K TPS, and partitions scale it linearly.
  • Q: What workload breaks serial execution? A: Long/interactive txns (stall the partition), cross-partition txns (2PC cost), and analytics scans (head-of-line blocking) — split OLAP off.
  • Q: Why stored procedures in VoltDB-style systems? A: The whole txn must arrive as one deterministic unit — no mid-transaction client round trips that would idle the serial slot.
  • Q: How does durability avoid capping throughput at fsync speed? A: Group commit batches many commits per fsync, or a replicated log (Raft/quorum) acks after one network RTT instead of one disk sync per txn.
  • Q: Cross-shard serializable transaction in one line? A: 2PC across shards for atomicity + serializable per shard, at the cost of coordinator blocking and 2+ RTT latency — avoid via entity-keyed routing.