Storage model
How writes flow through the delta, seal into immutable parts, and compact — plus storage policies and shards.
NYXDB's storage is shard-owned and lifecycle-driven. Understanding the delta → parts → compaction path explains both the freshness and the durability guarantees.
The write lifecycle
- Ingest & route — a write is decoded and routed to a shard.
- Journal + WAL — it is durably appended (group commit) to the write-ahead log for that table-shard.
- Delta — it lands in the in-memory write buffer (the committed tail), immediately query-visible as an overlay on the parts.
- PSI publish — the change is routed to subscribers (indexes, materialized views, streaming reads).
- Ack — the client is acknowledged at the durable group-commit watermark.
- Seal & flush (async, off the ack path) — the delta seals into an immutable part, with index regions built at seal time.
- Compaction — parts merge over time; indexes are rebuilt on merge.
The committed tail is bounded and indexed: it carries skip metadata so queries can prune it, and it seals off the write lock. Under memory pressure it can spill to disk (see memory governor).
Parts
Parts are immutable, single-file columnar segments (the NYXP format), sorted by the primary/sort key and granule-indexed. Each part carries its own secondary index regions in a CRC'd footer, so an index is recovered with its part — no separate rebuild on startup. Parts are published atomically (write temp → fsync → rename) and read under RCU snapshots, so readers never block writers.
Inspect parts with system.parts (part_id,
relation, shard_id, rows, size_bytes, min_key/max_key, disk, …).
Keyed parts & collapse
For keyed tables, records carry an operation and a sequence number, sorted by
(primary key…, sequence). Merge is latest-wins per key; delete tombstones drop
the key. This is what makes latest-per-key reads a bounded staircase rather than
a full history scan.
Storage policies
A named storage policy governs durability, delta flush triggers, index
placement, part movement, WAL binding, and compaction. Select one per table with
SETTINGS storage_policy = '…'. Policies observed in the engine include:
| Policy | Character |
|---|---|
memory_data | Memory-resident, no flush (ephemeral) |
disk_data | Disk-backed parts (append and keyed) |
default | Shipped fallback: memory disk, MergeTree, generous thresholds |
tiered / aged_tiered | Multi-pool with age-based movement |
Browse configured policies in
system.storage_policies and disks/pools in
system.disks.
TODO-verify: the full policy schema (pools, movement rules, TTL expressions) is deployment-specific. See Operations → Storage.
Shards
A shard is a logical partition of a table. Each shard owns its own delta, parts,
indexes, WAL slice, and PSI publication, so the write path is lock-free across
shards. Declare sharding with SETTINGS shard_by = '…', shards = N. Shard-level
min/max bounds and per-shard key digests prune shards before any scan.