Table of Contents

Pluggable Storage Backend (Persistent vs Transient)

One set of segment/index code, JIT-specialized per backend, so Transient components get heap speed for free.

Status: โœ… Implemented ยท Visibility: Internal ยท Category: Storage

๐ŸŽฏ What it solves

Every Typhon data structure โ€” segments, B+Trees, hash maps, chunk accessors โ€” needs to read and write 8 KiB pages. For durable components those pages live in the memory-mapped file and carry dirty tracking, eviction, and CRC protection; for StorageMode.Transient components (see Storage Modes) none of that applies โ€” the data is heap-only and gone on restart by design. Forking the segment/B+Tree/hash-map implementations to get a fast heap-only path would double the maintenance surface and risk the two copies drifting. The pluggable storage backend lets one implementation serve both cases at full speed for each.

โš™๏ธ How it works (in brief)

IPageStore is the abstraction every generic storage type is built against (where TStore : struct, IPageStore) โ€” never as a runtime-polymorphic field. Because the constraint is a struct, not a class, the JIT compiles a fully specialized copy of LogicalSegment<TStore>, ChunkBasedSegment<TStore>, ChunkAccessor<TStore>, BTree<TKey, TStore>, etc. per concrete backend, with zero virtual dispatch. Two backends ship in-tree: PersistentStore, a one-line forwarding wrapper around the memory-mapped page cache, and TransientStore, a heap-only store backed by pinned memory blocks. typeof(TStore) checks in hot paths (e.g. dirty tracking) are constant-folded per specialization, so a TransientStore build of ChunkAccessor literally has no dirty- tracking instructions left in it โ€” not a cheap no-op call, an absent one.

Sub-features

Sub-feature Backs Use it for
Persistent Store (MMF-backed) StorageMode.Versioned / SingleVersion Any durable component โ€” the default path, selected automatically
Transient Store (heap-backed) StorageMode.Transient Scratch data with StorageMode.Transient โ€” tune via TransientOptions

โš ๏ธ Guarantees & limits

  • IPageStore is [PublicAPI] for type-visibility reasons only โ€” it is not meant for external implementation; the two stores ship in-tree and selection is automatic from StorageMode, not something application code chooses directly.
  • Backend selection is per-component, decided at [Component(StorageMode = ...)] registration โ€” never mixed within a single segment.
  • PersistentStore is readonly struct (8 bytes, one pointer) with every method AggressiveInlining-forwarded to the page cache โ€” the abstraction costs nothing over calling the page cache directly.
  • TransientStore trades the persistence guarantees away entirely in exchange for the no-op dirty-tracking path โ€” see the Transient Store page for what that costs you.

๐Ÿงช Tests

  • StorageModeInfrastructureTests โ€” per-component backend selection via [Component(StorageMode = ...)]; confirms Versioned/SV/Transient never share a segment