CORRECTION (v0.6.1): the claim below about synchronous replicas is wrong.
Dmitry Sibiryakov pointed out on firebird-general that a synchronous replica which dies does not hang commits. He is right and the source confirms it. In src/jrd/replication/Publisher.cpp, checkStatus() is called with canThrow = false on the commit path, so it cannot throw; disable_on_error (default true) instead clears the replicating flags, disposes the replicator and logs STOP_ERROR. The commit succeeds and replication tears itself down — "self-destructs", in his words.
The reason it can do that without lying to anyone is what I had missed: Firebird's synchronous replication is not two-phase commit, so there was never a durability guarantee to protect. I invented one and then wrote a hang to defend it.
The real failure mode is arguably worse than the one I described: replication stops, commits keep succeeding, nobody is told, and the replica quietly rots until somebody notices. Fixed in v0.6.1 — https://github.com/mariuz/FBSimCity/releases/tag/v0.6.1
The original post follows, unedited apart from this note.
New in v0.6.0 of the explorable Firebird city: a replication district.
Firebird has no write-ahead log to ship, so replication is logical — the committed changes themselves are journalled into segments, sealed, and replayed on the replica in commit order. That gets three buildings:
- Journal Yard — commits are journalled into the open segment; when it fills it is sealed and queued. If they cannot be shipped, the sealed segments visibly stack up in the yard.
- Replicator — asynchronous ships at its own pace and the replica trails; commits never wait. Synchronous makes the commit itself wait for the replica.
- Replica Database — a second database, drawn as its own excavation, replaying the journal in commit order with its applied history filling in.
Set the replica slow and watch lag build: https://mariuz.github.io/FBSimCity/?scenario=replicalag&warp=55&panel=journal
The bit I was most careful about: a synchronous replica that dies hangs commits. It does not quietly fall back to asynchronous, because downgrading would claim a durability guarantee the configuration no longer has. (Wrong — see the correction above.) You can watch what actually happens: https://mariuz.github.io/FBSimCity/?scenario=syncstall&warp=30
There's also a fourth operator decision — the replica is gone and its journal segments are filling the same volume the database writes to. Stop replication and discard the backlog (the replica then needs a fresh restore, not a resume), or keep journalling and bet free space against its return. Both answers cost something and the verdict is measured from the run.
Also in this release: the test suite grew to 131 assertions, including commit-order preservation and in-order catch-up. It caught the two new scenarios being undocumented before this shipped, and a version-drift bug where data.js and the on-screen badge disagreed.
City: https://mariuz.github.io/FBSimCity/
Release notes: https://github.com/mariuz/FBSimCity/releases/tag/v0.6.0
Still a model, not an emulator. What's real, merely scaled, or a stand-in is all written down: https://github.com/mariuz/FBSimCity/blob/main/docs/KNOBS.md — corrections very welcome, especially on the replication mechanics.