You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Canonical design: cocoon-specs/design/meta-store.md — frozen at v2.28. This body is a summary; where they differ, the doc wins. The original inline design (v1) and the addendum comments below are superseded by the doc.
Motivation (measured)
Clone storms are dominated by the metadata layer, not virtualization: at B=64 with resident N≈190, the segments containing the two VM-index writes carry p50 2347ms + 867ms of a 4069ms clone while the FC snapshot load is 14ms. Every storage.Store[T] update rewrites the whole index plus a .prev copy under an exclusive flock (~1.8KB/record, 339KB×3 IO at N=192) ⇒ storm cost O(N·B). Removing a single RMW (#132/#145) measured inside host noise — the O(N) payload per write is the problem, and Store[T]'s whole-value semantics pin that cost model. Full data: cocoonstack/sandbox#30.
Decision summary
One record-granularity API, several engines (meta package): Scope-declared transactions with a single write namespace, per-transaction CommitMode (durable default, relaxed by explicit per-op opt-in), pure retryable closures, detached values, engine-neutral errors, Collection/Log primitives with domain repositories on top.
json is the first-class default engine — today's files, formats, .prev recovery and flocks move inside it; existing deployments upgrade untouched, no conversion. sqlite is the opt-in scale engine (one DB, namespace = table group, WAL, modernc.org/sqlite).
One meta.Store constructed at the command layer and injected into every backend — replacing five per-subsystem private store constructions.
GC and every metadata-backed destructive flow move to a revalidating tombstone protocol (lease fencing, phase-directed recovery, stable VMID-keyed entity locks outside cleanup sets), replacing lock-all orchestration. Bridge lane stays out (no persistent records).
Engine conversion is an explicit offline ops action (meta init / meta convert) with an engine-neutral manifest; config remains the sole backend authority.
P1 — protocol changes, still json-only: tombstone protocol, stable VM lock, vm rm restructure, retirement of gc.Module.Locker / Watchable.WatchPath / IndexFile/IndexLock.
P2 — the sqlite engine and everything that exists only for it; the measured win lands here.
P3 — optional: metering Log, networked engines, widening the relaxed set with data.
Status
Design frozen at v2.28 (v2.26-v2.28 were implementation-round amendments recorded in the doc header; v2.28 records the P2/P3 as-built decisions: generic (id, data) physical schema superseding the domain-typed sketch, flag-less meta commands with meta_backend as sole authority, referential name check, composition-root manifest guard for the json engine, and the SPI-layered Log/Seq with its opt-in metalog consumer). The doc moved to cocoon-specs — cocoon no longer carries design documents.
P2 — complete (PR meta: sqlite engine, offline conversion, and the metering log (P2+P3) #148): sqlite engine (WAL, durable/relaxed writer pair, ctx-bounded busy retry surfacing ErrBusy, identity/meta_state fail-closed verification, prepared-statement cache, background passive checkpoint); offline conversion with the §6 manifest protocol (both directions, crash-rerunnable, quiesce probes, aside retirement); cocoon meta init|convert|backup; contract suite passes both engines unmodified. Measured on the 16-core NVMe anchor host: durable update 366µs at N=10k vs json 31.9ms (87x), get 8.8µs vs 24.5ms, concurrent creates 909-1,693/s vs json 94-129/s at resident 1,000 — the §9 absolute gates hold with 13-57x headroom.
P3 — Log/Seq re-added (PR meta: sqlite engine, offline conversion, and the metering log (P2+P3) #148): SPI-layered primitive (identical semantics on both engines, zero engine code) with the metering.backend: meta consumer, Relaxed durability matching the file backend. Networked engines and relaxed-set widening stay data-gated per the doc.
Canonical design:
cocoon-specs/design/meta-store.md— frozen at v2.28. This body is a summary; where they differ, the doc wins. The original inline design (v1) and the addendum comments below are superseded by the doc.Motivation (measured)
Clone storms are dominated by the metadata layer, not virtualization: at B=64 with resident N≈190, the segments containing the two VM-index writes carry p50 2347ms + 867ms of a 4069ms clone while the FC snapshot load is 14ms. Every
storage.Store[T]update rewrites the whole index plus a.prevcopy under an exclusive flock (~1.8KB/record, 339KB×3 IO at N=192) ⇒ storm cost O(N·B). Removing a single RMW (#132/#145) measured inside host noise — the O(N) payload per write is the problem, andStore[T]'s whole-value semantics pin that cost model. Full data: cocoonstack/sandbox#30.Decision summary
metapackage):Scope-declared transactions with a single write namespace, per-transactionCommitMode(durable default, relaxed by explicit per-op opt-in), pure retryable closures, detached values, engine-neutral errors,Collection/Logprimitives with domain repositories on top..prevrecovery and flocks move inside it; existing deployments upgrade untouched, no conversion. sqlite is the opt-in scale engine (one DB, namespace = table group, WAL, modernc.org/sqlite).meta.Storeconstructed at the command layer and injected into every backend — replacing five per-subsystem private store constructions.meta init/meta convert) with an engine-neutral manifest; config remains the sole backend authority.Phasing
storage.Store[T]retires.vm rmrestructure, retirement ofgc.Module.Locker/Watchable.WatchPath/IndexFile/IndexLock.Log, networked engines, widening the relaxed set with data.Status
Design frozen at v2.28 (v2.26-v2.28 were implementation-round amendments recorded in the doc header; v2.28 records the P2/P3 as-built decisions: generic
(id, data)physical schema superseding the domain-typed sketch, flag-lessmetacommands withmeta_backendas sole authority, referential name check, composition-root manifest guard for the json engine, and the SPI-layeredLog/Seqwith its opt-in metalog consumer). The doc moved to cocoon-specs — cocoon no longer carries design documents.meta.Store;storage.Store[T]retired; byte-fidelity goldens + differential value/error traces for every namespace.Store.Events; protocol gates (fencing/ABA, subset recovery, shared-lease escalation, 256-process storm, durable-ack ordering) all green.ErrBusy, identity/meta_statefail-closed verification, prepared-statement cache, background passive checkpoint); offline conversion with the §6 manifest protocol (both directions, crash-rerunnable, quiesce probes, aside retirement);cocoon meta init|convert|backup; contract suite passes both engines unmodified. Measured on the 16-core NVMe anchor host: durable update 366µs at N=10k vs json 31.9ms (87x), get 8.8µs vs 24.5ms, concurrent creates 909-1,693/s vs json 94-129/s at resident 1,000 — the §9 absolute gates hold with 13-57x headroom.Log/Seqre-added (PR meta: sqlite engine, offline conversion, and the metering log (P2+P3) #148): SPI-layered primitive (identical semantics on both engines, zero engine code) with themetering.backend: metaconsumer, Relaxed durability matching the file backend. Networked engines and relaxed-set widening stay data-gated per the doc.