Inspired by Tree rings (dendrochronology)
Dendrite Ring
Counterpart to Fixed-interval time-series retention
Time-series retention with variance-proportional rings: thin rings for quiet periods, wide rings for incidents, and a sapwood-to-heartwood lifecycle for aging data.
benchmarked

01
Key properties
- 01O(1) amortized ingest via Welford streaming statistics
- 02Variance-proportional encoding: thin rings (48 bytes) for boring periods, wide rings (196-292 bytes) for incidents
- 03CUSUM + EWMV change-point detection drives ring boundaries automatically
- 048-class shape classification (Flat, RampUp, RampDown, Spike, SpikeRecover, Oscillating, StepUp, StepDown)
- 05Sapwood/heartwood lifecycle: recent rings mutable, aged rings immutable with summarized statistics
- 06O(log a) anomaly range queries via sorted anomaly index
02
Operation complexity
Side-by-side with the classical counterpart.
| Operation | Dendrite Ring | Fixed-interval time-series retention |
|---|---|---|
| ingest | O(1) amortized | O(1) |
| ring_at | O(log r) | O(log n) (B-tree) |
| rings_in_range | O(log r + k) | O(log n + k) |
| anomalies_in_range | O(log a + k) | N/A |
| rings_by_shape | O(r) | N/A |
| tick (heartwood transition) | O(t) | N/A |
| space (per ring) | 48-292 bytes | Fixed per interval |
03
Interface preview
pub struct DendriteStore { /* ... */ }
impl DendriteStore {
pub fn new(config: DendriteConfig) -> Self;
pub fn with_preset(preset: MetricPreset) -> Self;
pub fn ingest(&mut self, timestamp: u64, value: f64)
-> Result<Option<&DendriteRing>, DendriteError>;
pub fn ring_at(&self, timestamp: u64) -> Option<&DendriteRing>;
pub fn anomalies_in_range(&self, start: u64, end: u64) -> &[AnomalyEntry];
pub fn rings_by_shape(&self, shape: ShapeClass) -> Vec<&DendriteRing>;
pub fn tick(&mut self) -> usize;
pub fn storage_profile(&self) -> StorageProfile;
}04
Where this matters
Prometheus · TSDB Block Compaction
| Today | With Dendrite Ring | How |
|---|---|---|
| Fixed 2-hour blocks regardless of signal | Variance-proportional ring widths | CUSUM/EWMV detects regime changes; thin rings for quiet periods, wide for incidents |
| Uniform storage cost for all time ranges | 48 bytes for boring periods, 292 bytes for incidents | Ring summary fidelity scales with signal variance |
05
Interactive simulation
Live metric stream
sapwood, thinsapwood, wideheartwood
Field notes
- Waiting for the first sample…
- Rings
- 0
- Sapwood
- 0
- Heartwood
- 0
- Wide / thin
- 0 / 0
- Bytes
- 0 B
- Regime
- calm
Tick 0 / 300Thin 48 B · wide 196–292 B · sapwood = last 6 rings
Figure. Dendrite Ring Growth at tick 0 of 300. Thin 48 B · wide 196–292 B · sapwood = last 6 rings.
Illustrative simulation, not a benchmark · Mutuus Research, ByteQuilt
Discussion