Versioned
Full MVCC snapshot isolation and zero-loss durability for data that can never be lost or read torn.
Status: โ Implemented ยท Visibility: Public ยท Level: ๐ข Start Here ยท Category: Ecs
๐ฏ What it solves
Some component data โ inventory, currency, guild membership, progression โ must never be lost on crash, must
never be visible to a concurrent transaction in a half-written state, and sometimes needs to be read "as of" a
prior point in time. Versioned is Typhon's default storage mode: every write is isolated until commit, every
commit is WAL-durable, and concurrent readers always see a consistent value.
โ๏ธ How it works (in brief)
A Versioned component keeps a per-entity revision chain alongside its data. EntityRef.Write<T>() is
copy-on-write โ it allocates a new revision and copies forward rather than overwriting in place, so concurrent
readers keep seeing the prior committed value until your transaction commits. Every transaction is WAL-logged;
on commit the new revision becomes the visible HEAD and is durable. Reads walk the chain under transaction-
sequence-number visibility, giving each transaction a consistent snapshot of the data.
๐ป Usage
[Component("Game.Inventory", 1)] // StorageMode.Versioned is the default โ no need to set it explicitly
public struct Inventory
{
[Index] public int ItemId;
public int Quantity;
}
[Archetype]
partial class Player : Archetype<Player>
{
public static readonly Comp<Inventory> Inventory = Register<Inventory>();
}
using var tx = dbe.CreateQuickTransaction();
var id = tx.Spawn<Player>(Player.Inventory.Set(new Inventory { ItemId = 7, Quantity = 1 }));
tx.Commit();
using var tx2 = dbe.CreateQuickTransaction();
var e = tx2.OpenMut(id);
ref var inv = ref e.Write(Player.Inventory);
inv.Quantity += 1; // copy-on-write โ old revision still visible to concurrent readers
tx2.Commit(); // new revision becomes HEAD, durable
โ ๏ธ Guarantees & limits
- Zero data loss on crash โ every committed write is WAL-durable and recoverable to the exact pre-crash state.
- Full snapshot isolation: concurrent transactions never see another transaction's uncommitted writes; conflicting writes are detected at commit.
tx.Rollback()discards the staged revision entirely โ the prior committed value is untouched.- The most expensive mode: ~250 ns/write versus ~40 ns for
SingleVersion/Transientโ ~6ร (copy-on-write allocation, revision-chain append, eventual chain GC). - Carries per-entity chain memory overhead even when a component is rarely written.
- Required for
ReadsSnapshot/ temporal "AS OF" reads and TAIL (committed-value) indexes โ these guarantees areVersioned-only;SingleVersionandTransientreject them.
๐งช Tests
- EcsSpawnMvccTests โ copy-on-write on
Write, concurrent transaction still seeing old data, rollback freeing the new chunk, revision-chain creation
๐ Related
- Sibling: Committed Durability Discipline โ gets
Versioned-grade commit atomicity on the cheaperSingleVersionlayout, for writes that don't need snapshot isolation - Sibling: Revision โ the MVCC revision-chain subsystem
Versionedwrites append into - Parent feature: Storage Modes