data-plane: honest SketchStore memory diagnostic + idle-sid eviction - #356
Merged
Merged
Conversation
`SketchStore::approx_memory_bytes` is the flusher's evictable-payload gauge (current_epoch + sealed payloads). At idle it correctly reads ~0 because payloads are flushed to disk — but the per-sid registry (`instances` metadata + per-series `InternTable` label caches) stays resident, so the MEMORY_DIAG line read "0.00 KB" while process RSS sat in the hundreds of MB, and there was no relief valve for that residue (stale sketch sids are pinned until config-driven retirement). Two cohesive changes, both scoped to the SketchStore: 1. Honest memory diagnostic. Adds `InternTable::approx_heap_bytes` and `SketchStore::approx_resident_bytes` (registry metadata + intern caches + live payload) and `process_resident_bytes()` (/proc/self/statm). The 30s MEMORY_DIAG line now logs payload (evictable) / registry+intern (resident, not flushable) / process RSS, so the real footprint is visible. The flusher's payload-pressure trigger is intentionally left on the payload gauge — feeding non-flushable registry memory into it would livelock the flush loop (it can only evict payload). 2. Idle-sid eviction (opt-in --idle-sid-evict-secs / ASAP_IDLE_SID_EVICT_SECS, default 0 = off). A periodic sweep drops the in-memory `SidStoreData` (epoch columns + intern cache + series slot) for sketch sids that are persistence-backed, write-idle past the threshold, AND fully durable on disk (sealed_epochs + current_epoch empty), while KEEPING the queryable `SketchInstanceMetadata`. `union_disk_parts_into` reads the durable tier via the retained metadata only (never `self.series`), so an evicted series stays answerable from disk; the append path's `entry().or_insert_with` rehydrates a fresh store on the next write. Bounds resident registry memory under series churn. Effective idle horizon is max(threshold, persistence_hot_window) since eviction waits for a sid's windows to seal+flush first. Adds `SidStoreData::last_write_unix_ms`, stamped under the append write lock the hot path already holds (no extra cost). 5 unit tests cover resident accounting and the eviction predicate / rehydration / durability guard. Validated live on the Google-cluster trace: 31.5k stale sids reclaimed, in-memory sid state held to a few thousand vs pinning all 36k; MEMORY_DIAG now shows payload≈KB / registry≈MB / RSS≈MB instead of a misleading 0.00 KB. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Sep 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Driving the Google-cluster trace through the agent → data-plane stack surfaced two SketchStore memory issues:
SketchStore::approx_memory_bytesis the flusher's evictable-payload gauge (current_epoch+ sealed payloads). Once payloads flush to disk it reads ~0 — but the per-sid registry (instancesmetadata + per-seriesInternTablelabel caches) stays resident. The 30sMEMORY_DIAGline read0.00 KBwhile process RSS sat at hundreds of MB (e.g. 36,484 idle sids → ~600 MB RSS reported as0.00 KB).Expiredsids (config-/retention-driven), so a series that goes quiet pins its in-memory state indefinitely. Under cardinality churn this grows unbounded (observed: a long-running stack at 210k sids / 3.6 GiB / 496 GB disk).Changes (both scoped to the SketchStore)
1. Honest memory diagnostic
InternTable::approx_heap_bytes+SketchStore::approx_resident_bytes— registry metadata + intern caches + live payload.process_resident_bytes()reads/proc/self/statmfor ground-truth RSS.MEMORY_DIAGnow logs payload (evictable) / registry+intern (resident, not flushable) / process RSS.2. Idle-sid eviction — opt-in
--idle-sid-evict-secs/ASAP_IDLE_SID_EVICT_SECS(default0= off)SidStoreData(epoch columns + intern cache +seriesslot) for sketch sids that are persistence-backed, write-idle past the threshold, and fully durable on disk (sealed_epochs+current_epochempty) — while keeping the queryableSketchInstanceMetadata.union_disk_parts_intoreads the durable tier via the retained metadata only (neverself.series), so an evicted series stays answerable from disk; the append path'sentry().or_insert_withrehydrates on the next write. This is the same disk-read path the normal flush-evict loop and restart-recovery already rely on.max(threshold, persistence_hot_window).SidStoreData::last_write_unix_ms, stamped under the append write lock already held (no extra hot-path cost).Tests
5 new unit tests: resident accounting (registry counted when payload is 0; grows with interned label cardinality), eviction predicate, rehydration-on-write, and the durability guard (recent + pending-data sids spared).
cargo test -p data_plane --libgreen.Live validation (Google-cluster trace, multinode)
payload=4207 KB (evictable) / registry+intern≈37 MB (resident) / process RSS=131 MBinstead of0.00 KB.Notes
0).feat/sum-aggregation-type); retarget tomainonce that merges.kind=exactbecause the agent ships degenerate ε=0 DDSketch frames (the controller policy correctly declaresalpha: 0.02, but registered sids carryrelative_accuracy: 0.0) — an ASAPCollector emit/processor gap, not addressed here.🤖 Generated with Claude Code