FBSimCity — an explorable city of Firebird internals
🔥">
Control room
Scenario
— pick a scenario —<br>Steady state<br>Cache thrash<br>Stuck OIT / version bloat<br>Lock contention<br>Rush hour<br>Sweep storm<br>Nightly gbak on a busy DB<br>nbackup with delta
Query rate
Write mix
Page cache
Sweep interval
Automatic sweep
Long-running transaction<br>pins the OIT — garbage piles up
Sweep now<br>Rush hour ×60
Backup yard
gbak<br>nbackup L0<br>L1
Lock / unlock<br>Restore chain
drag to pan · scroll to zoom · click a building
← Back<br>Next →
Query trace
Auto play<br>Next step →
Keyboard & mouse
dragpan the city<br>scroll / pinchzoom<br>clickbuilding story<br>←→↑↓pan<br>+ / −zoom in / out<br>spacepause / resume the simulation<br>Tguided tour<br>Gtrace one query, step by step<br>Pdata-page anatomy<br>Dday / night theme<br>?this help<br>Escclose overlays
Anatomy of a Firebird data page
Every table lives on data pages inside the single database<br>file. Record descriptors grow from the top, record data grows from the<br>bottom, and free space sits in between — and every record carries its<br>transaction of origin plus a pointer to its previous version.
page header — type=DATA, flags, checksum/SCN, generation
dpg_sequence · dpg_relation (table id) · dpg_count (records)
descriptor[0] — offset, length
descriptor[1] — offset, length
descriptor[2] — offset, length
free space<br>(descriptors grow ↓ · records grow ↑)
rpb: txn 1042 · back version → p118/l3 · flags · format#<br>record 2 — RLE-compressed data
rpb: txn 1017 · back version → none · flags · format#<br>record 1 — RLE-compressed data
rpb: txn 998 · back version → none · flags · format#<br>record 0 — RLE-compressed data
The version chain
newest version<br>txn 1042 — what new snapshots see
↓ back pointer (delta)
older version<br>txn 981 — still visible to older snapshots
↓ back pointer (delta)
oldest version<br>below the OIT — garbage, awaiting GC / sweep
A reader walks down the chain until it finds the<br>version its transaction snapshot is allowed to see. Versions below<br>the Oldest Interesting Transaction are demolished by cooperative GC<br>or the sweep. Back versions are stored as deltas, usually on the<br>same page — this is Firebird's multi-generational architecture, and<br>why it needs no rollback segment and no WAL.