Thursday, July 30, 2026

FBSimCity v0.4.0: the backup yard — gbak pins the OIT, nbackup fills the delta

FBSimCity — the explorable isometric city of Firebird internals — is at v0.4.0, and this release adds a whole backup yard, built around what gbak and nbackup actually do.

gbak: the backup that pins your OIT

gbak takes a logical backup online: it attaches like any other client and reads every table through a snapshot transaction. That snapshot is the interesting part — it pins the OIT for the entire run. Garbage collection stalls, cooperative GC refuses to demolish anything, and the record version towers climb until the backup finishes.

This is why a nightly gbak against a busy database and a mysteriously bloating database are so often the same story. Now you can watch it happen instead of inferring it from gstat -h:

Run the nightly gbak scenario →

nbackup and the difference file

nbackup is the other half: a physical backup, incremental by level. Level 0 copies the whole file, level 1 only the pages changed since level 0, and so on. The chain is enforced in the model just as it is in reality — ask for a level 1 without a level 0 and it refuses, and Restore chain reports which levels a restore would have to apply, in order. Lose level 0 and the rest are waste paper.

Locking the database (nbackup -L) freezes the main file so it can be copied safely while the server keeps running. Every page written from that moment lands in the difference file instead — a new orange pit beside the main excavation that fills up visibly and merges back on unlock. Forget to unlock, and it grows for as long as you watch:

See a locked database filling its delta →

Dirty pages stopped being free

I also fixed a genuine falsehood in the simulation. Evicting a dirty buffer used to cost nothing, which quietly understated write pressure. It now writes the page out first, so a reader that needs a frame pays for somebody else's write.

The interesting consequence is what it does not do. Because commits flush their page under forced writes (Firebird's default), dirty evictions stay rare on a healthy database — around 1% of evictions — and only start biting when the cache is too small for the working set, reaching about 5% at 16 buffers. The honest lesson is "your cache is undersized", not "writes are bad", and the new evictions (dirty N) readout shows exactly that.

A knob audit

Since the whole point of this thing is intuition rather than emulation, v0.4.0 also documents itself. docs/KNOBS.md lists every control and readout, what it does to the model, and whether the mechanism is real, merely scaled, or a plausible modeled stand-in — followed by the deliberate simplifications, written down so nobody has to discover them by reading sim.js. Sweep here is time-triggered rather than transaction-gap-triggered; lock contention is a probability, not a wait-for graph; no SQL is parsed. It is all in the table.

Also in this release

  • Subsystem controls now live on the subsystem: start a sweep from the GC depot, run backup levels or lock the database from the nbackup vault, forget to commit a transaction from the Transaction Hall.
  • The screenshot driver no longer leaks browser profiles, and form controls are 16px so iOS Safari stops zooming the page.

City: mariuz.github.io/FBSimCity
Release notes: v0.4.0
Source: github.com/mariuz/FBSimCity (MIT, plain HTML/JS, no build step)

Corrections are very welcome, especially on the backup mechanics — I modeled those from the documentation rather than from the engine source.

FBSimCity is an independent educational project, not affiliated with or endorsed by the Firebird Project. Firebird® is a registered trademark of the Firebird Foundation Incorporated.

No comments: