VeltrixDB Docs
v1.1.0 GitHub FAQ Quickstart

Admission Control & GC

VeltrixDB continuously measures read latency and uses it as a feedback signal to throttle writes and pace VLog garbage collection — protecting foreground reads from being starved by background write and reclaim traffic.

Scope This page covers the admission-control ladder and its interaction with GC. For VLog internals, block packing, and the LIRS cache, see Storage Engine.

Why admission control exists

NVMe bandwidth and IOPS are shared between three consumers: foreground reads, foreground writes, and background VLog GC. Without coordination, a burst of write traffic (or a GC pass reclaiming a large garbage backlog) can saturate the disk queue and push read tail latency into double-digit milliseconds. VeltrixDB's admission control closes this loop automatically: it watches read latency and, when it degrades, throttles the traffic that is competing with reads — rather than requiring an operator to manually cap write rate or pause GC during an incident.

The read-latency EWMA

Every Get() call feeds an exponentially-weighted moving average of read latency (ReadLatencyEWMANs). This single signal drives every decision described below.

To keep the EWMA update itself from becoming a bottleneck at multi-million-ops/sec read throughput, the CAS-loop update is sampled 1-in-64 reads rather than run on every read — at 2M reads/sec this adds at most ~32 microseconds of lag to the signal, far below the millisecond-scale thresholds it drives.

The admission-control ladder

As read latency rises, VeltrixDB escalates through a small set of protective actions:

Read EWMAAction
< 3 msNormal — GC runs at full speed
≥ 3 msGC bandwidth capped at 60 MB/s
≥ 4 msGC paused entirely, and each PUT sleeps 2 ms before submitting to WAL/VLog
< 2 msEverything resumes — throttle cleared, GC unpaused
No reads for 4 minutesEWMA is treated as stale — GC resumes automatically

Two things are worth calling out about this ladder:

The staleness guard

If no Get() call arrives for 4 minutes, the EWMA is treated as stale and GC is unconditionally resumed. Without this guard, a single slow read early in a write-only workload (e.g. a bulk load or benchmark with no read traffic) could latch the EWMA above the throttle threshold and never clear it — permanently blocking VLog GC because there are no subsequent fast reads to bring the average back down. The staleness window is tracked via LastReadNs, stamped on every Get().

Interaction with VLog GC tiers

The read-EWMA ladder above and the garbage-ratio-driven GC tiers (see Storage Engine: VLog GC tiers) are two independent signals that combine at GC decision time:

Garbage ratioGC bandwidthAdmission pause honored?Defrag interval
< 30%No GC
30–50%Unlimited / 60 MB/sYes120 s
50–65% (critical)Unlimited / 200 MB/sYes60 s
≥ 65% (emergency)UnlimitedNo30 s

In plain terms: as long as garbage is below 65%, a paused-by-admission-control state (read EWMA ≥ 4 ms) is honored — GC stands down and gives reads the full disk. Only once garbage crosses the 65% emergency threshold does GC override that pause. This ordering is deliberate: below 65%, protecting read latency is the priority; above 65%, the system is already in enough trouble that continuing to defer GC would make things categorically worse.

The emergency tier: breaking the death spiral

The scenario the emergency tier exists to prevent: read latency rises → admission control pauses GC → garbage keeps accumulating because nothing reclaims it → VLog grows → cache hit rate drops (more cold data to page through) → read latency rises further → GC stays paused indefinitely. This is a genuine death spiral — without an escape hatch, a transient latency spike can turn into a permanent, self-reinforcing degradation.

At ≥ 65% garbage ratio, VeltrixDB breaks the cycle unconditionally: GCPaused is bypassed, GC bandwidth is uncapped, and the defrag interval is quartered so the system checks in on the disk far more frequently. Every emergency pass logs loudly:

[gc] disk=N EMERGENCY  garbage=67.2%  ewma=21.4ms  bypassing admission-control pause to escape death spiral

and increments veltrixdb_vlog_gc_emergency_runs_total.

Treat emergency GC as an incident, not routine operation The emergency tier is a safety valve, not a steady-state mode. If you regularly see veltrixdb_vlog_gc_emergency_runs_total incrementing, it means sustained write rate is outpacing GC reclaim throughput on that disk — add IOPS headroom or reduce write load rather than relying on the emergency override to keep up indefinitely.

Operational guidance

Metrics to watch

MetricWhat it tells you
veltrixdb_vlog_garbage_ratioCurrent dead-space fraction of the VLog per disk. Drives which GC tier is active.
veltrixdb_vlog_gc_emergency_runs_totalCount of GC passes that bypassed the admission-control pause. Should be at or near zero in steady state.
veltrixdb_storage_write_admission_throttles_totalCount of PUT operations delayed by the write-throttle ladder. Non-zero indicates read latency has crossed the throttle threshold.

Healthy pattern

In a well-provisioned cluster, the garbage ratio oscillates within the 30–50% band, GC bandwidth stays at the normal cap, the write-admission-throttle counter is flat at zero (or increments only briefly during isolated traffic spikes and then stops), and the emergency-runs counter never moves. Read EWMA stays comfortably under the 3 ms first-tier threshold under normal load.

Unhealthy pattern

Watch for these signals together, since any one in isolation can be a false alarm but the combination is not:

This combination means write rate has outpaced GC reclaim capacity on one or more disks for a sustained period. The fix is capacity, not configuration: add NVMe IOPS/bandwidth headroom, reduce write rate to the affected disks, or check for a hot-shard skew that is concentrating write traffic on a single disk (see the shard-to-disk routing model in Storage Engine).