···11+# Generational Read Version
22+33+In FoundationDB, transactions are not allowed to span generations.
44+During recovery, the current database version is advanced by 100 million (100 seconds).
55+Because the mvcc window is only 5 million (5 seconds),
66+this effectively kills any transactions that were in-progress during the recovery;
77+they will fail with `transaction too old`.
88+99+There are a couple of reasons for this design.
1010+1111+For one, the new generation comes with a completely new set of stateless processes,
1212+including a new Resolver.
1313+The new Resolver does not have the last 5M versions of writes in-memory,
1414+so it can't perform concurrency control for any transactions spanning the recovery.
1515+Fast-forwarding the database version fixes this:
1616+these transactions will never reach the Resolver because post-recovery they will always be considered too old.
1717+1818+The second reason is considerably more subtle.
1919+On storage servers,
2020+writes are applied eagerly to the in-memory ptree before they are actually considered committed (fully replicated).
2121+This is safe because clients cannot receive a read version to read these mutations until after the CommitProxy acks the version
2222+(to the Master a.k.a. Sequencer), which only happens once the batch is fully replicated.
2323+This eager fetching effectively pipelines the commit process, saving latency;
2424+by the time a client is able to receive a new read version the mutations are likely already on the Storage servers,
2525+so the extra hop from TLogs to Storage is effectively nullified.
2626+2727+The performance improvement comes at the cost of some complexity:
2828+during a recovery uncommitted mutations can be lost (an unavoidable property of a fault-tolerant system),
2929+and this means Storage servers must be able to "undo" uncommitted mutations.
3030+FDB solves this elegantly:
3131+due to its MVCC model, the last 5M versions of mutations are stored *only* in-memory on Storage servers,
3232+and are not written to disk.
3333+When a Storage server notices that a recovery has occurred, it undoes all in-memory locations by literally just killing itself.
3434+After restarting it will no longer read mutations past the end of the previous generation before moving on,
3535+effectively skipping the uncommitted versions.
3636+3737+(Note that this means the range of partially-committed batches on TLogs cannot be allowed to exceed 5M versions,
3838+which is an incredibly subtle gotcha.)
3939+4040+So the problem is that if we do *not* fast-forward during recovery,
4141+a new transaction with a read version from the new generation's Sequencer could attempt to read uncommitted mutations from the *last* generation.
4242+That is, if we did not fast-forward, the generations' version ranges could *overlap* and there would be confusion about which mutations are being read.
4343+The fast-forward fixes this because it effectively skips over those versions in the "history" of the database.