Build a B-tree storage engine (SQLite-style) (11 scenes)
Scene 10 · Design canvas — size a SQLite deployment
Workloads pick different knob combinations; each knob has a 'too low' and 'too high' failure mode you can name from earlier scenes.
Previously
You now know every layer — pages, B-trees, descents, splits, indexes, page cache, WAL, checkpoint. Time to pick knob settings for three real workloads and name the scene that backstops every choice.
Scene 10
Design canvas — size a SQLite deployment
Diagram
LEFT: a workload selector (write-heavy logging / read-heavy reference / OLTP). MIDDLE: six knobs — page_size, journal_mode, synchronous, cache_size, # indexes, wal_autocheckpoint — each labeled with the scene id its failure mode lives in. RIGHT: a simulation panel — throughput, p99 latency, durability window, file growth, a WAL-size sparkline, and a stack of FAILURE FLAGS that each cite a specific earlier scene when they fire.
Workload
OLTP
mixed read/write, durability matters
~5 k commit/s target
Throughput
~5 k commit/s
p99 Latency
~2 ms / commit
Durability
0 — fsync per commit
File Growth
stable; bounded WAL
Knobs (6)
- page_size4 KB
- journal_modeWAL
- synchronousFULL
- cache_size64 MB
- # indexes2
- wal_autocheckpoint1000 frames
- btree-07-page-cache · cache_size too small for working set2 MB cache + a 100-page hot set = LRU thrash; misses become real disk I/O.
- btree-06-indexes · too many indexes for a write-heavy workloadEvery INSERT updates every index B-tree; throughput drops ~linearly with index count.
- btree-09-checkpoint · no auto-checkpoint with continuous writesWAL never rewinds; the file grows on every commit until something else fires a checkpoint.
- btree-08-wal-and-fsync · synchronous=OFF in a workload that needs durabilityA power-loss can lose recent commits AND corrupt the DB; only choose OFF for rebuildable data.
- btree-05a-delete-and-vacuum · VACUUM never run on a heavy-delete workloadDeletes free cells inside pages but don't shrink the file; the DB grows monotonically.
- btree-08-wal-and-fsync · rollback journal blocks readers under writesSwitch to WAL when concurrent readers exist — DELETE journal serializes them behind the writer.
- btree-02-pages · 1 KB pages misalign with the OS blockPages smaller than the 4 KB OS block become partial-block reads, doubling I/O per page.
- btree-02-pages · 64 KB pages waste bandwidth on point readsEach lookup pulls 16x the bytes of a 4 KB page — fine for scans, painful for random reads.
workload: OLTP — every failure flag links to the scene it lives in
Open on a larger screen for the full design canvas.
Workload selector — three opinionated presets.
Knob panel — each row shows the scene id its failure mode lives in.
Simulation — throughput, latency, durability, WAL size.
Failure flags carry the scene id they trace to (e.g. btree-07-page-cache).
OLTP defaults pre-loaded. The verifier walks each knob and confirms it against its scene; meters settle into the green band before you take over.
Implementation
verifier(workload, knobs)
every fired rule cites the scene its failure mode lives in
1def verifier(workload, knobs):2 flags = []3 if knobs.cache_size < workload.working_set:4 flags.push('btree-07-page-cache') # LRU thrash5 if workload.write_heavy and knobs.indexes >= 3:6 flags.push('btree-06-indexes') # write-amp7 if knobs.synchronous == OFF and workload.durable:8 flags.push('btree-08-wal-and-fsync')9 if (knobs.journal_mode == WAL and10 knobs.wal_autocheckpoint in (OFF, HUGE) and11 workload.has_writes):12 flags.push('btree-09-checkpoint') # WAL grows13 if knobs.journal_mode == ROLLBACK and workload.concurrent_readers:14 flags.push('btree-08-wal-and-fsync')15 if knobs.page_size != OS_BLOCK:16 flags.push('btree-02-pages') # I/O amp17 return flags
defaults_for(workload)
preset knob map — the 'opinionated good config' per workload
1def defaults_for(workload):2 if workload == 'logging':3 return Knobs(page_size=4KB, journal=WAL,4 synchronous=NORMAL, cache=64MB,5 indexes=0, wal_autockpt=1000)6 if workload == 'reference':7 return Knobs(page_size=4KB, journal=WAL,8 synchronous=FULL, cache=256MB,9 indexes=2, wal_autockpt=1000)10 if workload == 'oltp':11 return Knobs(page_size=4KB, journal=WAL,12 synchronous=FULL, cache=64MB,13 indexes=2, wal_autockpt=1000)
commit_path_under(knobs)
what scenes 8 + 9 do for the chosen journal + sync combo
1def commit_path_under(knobs):2 mutate_page_in_cache() # btree-073 if knobs.journal_mode == ROLLBACK:4 write_rollback_journal() # readers wait5 fsync_journal()6 write_pages_in_place_to_db()7 else: # WAL8 append_frame_to_wal() # btree-089 if knobs.synchronous >= FULL:10 fsync_wal() # per-commit cost11 elif knobs.synchronous == NORMAL:12 pass # fsync at checkpoint13 if wal_frames() >= knobs.wal_autockpt:14 checkpoint() # btree-09