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 a specific earlier scene.
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
- Watch
- Try it
- Predict
- Capture
- 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.
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.
Highlighted lines are the ones running in the diagram right now.
def verifier(workload, knobs):flags = []if knobs.cache_size < workload.working_set:flags.push('btree-07-page-cache') # LRU thrashif workload.write_heavy and knobs.indexes >= 3:flags.push('btree-06-indexes') # write-ampif knobs.synchronous == OFF and workload.durable:flags.push('btree-08-wal-and-fsync')if (knobs.journal_mode == WAL andknobs.wal_autocheckpoint in (OFF, HUGE) andworkload.has_writes):flags.push('btree-09-checkpoint') # WAL growsif knobs.journal_mode == ROLLBACK and workload.concurrent_readers:flags.push('btree-08-wal-and-fsync')if knobs.page_size != OS_BLOCK:flags.push('btree-02-pages') # I/O ampreturn flags
def defaults_for(workload):if workload == 'logging':return Knobs(page_size=4KB, journal=WAL,synchronous=NORMAL, cache=64MB,indexes=0, wal_autockpt=1000)if workload == 'reference':return Knobs(page_size=4KB, journal=WAL,synchronous=FULL, cache=256MB,indexes=2, wal_autockpt=1000)if workload == 'oltp':return Knobs(page_size=4KB, journal=WAL,synchronous=FULL, cache=64MB,indexes=2, wal_autockpt=1000)
def commit_path_under(knobs):mutate_page_in_cache() # btree-07if knobs.journal_mode == ROLLBACK:write_rollback_journal() # readers waitfsync_journal()write_pages_in_place_to_db()else: # WALappend_frame_to_wal() # btree-08if knobs.synchronous >= FULL:fsync_wal() # per-commit costelif knobs.synchronous == NORMAL:pass # fsync at checkpointif wal_frames() >= knobs.wal_autockpt:checkpoint() # btree-09
Where this sits in Build a B-tree storage engine (SQLite-style)
Scene 10 of 11, in the Design canvas act — Size SQLite for write-heavy logging, read-heavy reference, OLTP.. Workloads pick different knob combinations; each knob has a 'too low' and 'too high' failure mode you can name from earlier scenes.
All 11 scenes in Build a B-tree storage engine (SQLite-style) · Every curriculum