Skip to content

fix(memory): tick-path eviction spills collections instead of plain-dropping (task #45)#312

Merged
pilotspacex-byte merged 1 commit into
mainfrom
fix/tick-eviction-spill
Jul 13, 2026
Merged

fix(memory): tick-path eviction spills collections instead of plain-dropping (task #45)#312
pilotspacex-byte merged 1 commit into
mainfrom
fix/tick-eviction-spill

Conversation

@pilotspacex-byte

@pilotspacex-byte pilotspacex-byte commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Task #45 — root cause of the recurring Linux-CI stable-GHOST flake (cold_collection_visibility: EXISTS=1 but LRANGE/ZRANGE empty). Three compounding defects:

  1. evict_one_with_spill (src/storage/eviction.rs) gated spilling behind a stale is_string check even though spill_to_datafile had full collection support — collection victims under a live SpillContext were silently plain-dropped.
  2. Even spilled string victims never got a ColdIndex entry — durable file existed but was unreachable.
  3. The periodic tick (shard::timers::run_eviction) never received a SpillContext at all — every tick-evicted collection was plain-dropped even with disk-offload + appendonly enabled. persistence_tick.rs now builds a real SpillContext from the shard manifest when disk-offload is enabled, fail-close otherwise (policy semantics unchanged).

Verification

Fixes the flake class that has been rerolled manually on multiple PRs (incl. #299/main runs 29189049422, 29186983648). Task #44 (crash_recovery_disk_offload_no_aof pre-existing failure) may be affected — will recheck after merge.

Refs: task #45, #41/#8 precedents.

Summary by CodeRabbit

  • Bug Fixes
    • Collection values evicted during routine maintenance are now spilled to durable storage instead of being silently dropped when disk offload is configured.
    • Successfully spilled values are registered for later retrieval.
    • Failed spill operations now retain the active value rather than deleting it.
    • Eviction continues to safely fall back to dropping values when no durability backstop is available.
  • Tests
    • Added regression coverage for collection spilling and periodic eviction behavior.

… of plain-dropping them

Root-causes the intermittent tests/cold_collection_visibility.rs CI flake
(stable GHOST: EXISTS == 1 but LRANGE/ZRANGE/HGETALL/SMEMBERS permanently
empty; reproduced on unmodified main, only on shared/slow Linux runners).

Two compounding defects in storage::eviction::evict_one_with_spill (the
synchronous spill path shared by the tick, the memory-pressure cascade's
sync-spill fallback, and db_quota):

1. Collection victims (Hash/List/Set/ZSet/Stream) were gated behind a
   stale `is_string` check predating kv_spill::spill_to_datafile's full
   collection support (it already serializes any RedisValueRef via
   kv_serde) — a collection victim under a live SpillContext silently
   plain-dropped, indistinguishable from spill: None.
2. Even string victims never registered a ColdIndex entry after a
   successful sync spill (spill_to_datafile was always called with
   cold_index: None) — the durable .mpf file existed and was manifest-
   registered, but nothing could ever read it back.

Separately, shard::timers::run_eviction (the periodic 100ms tick,
independent of the memory-pressure cascade) never received a SpillContext
at all — every victim it picked was plain-dropped even with
--disk-offload enable and a durability backstop (--appendonly yes)
configured. shard::persistence_tick::run_eviction_tick now builds a real
SpillContext (ShardManifest + shard data dir + next_file_id) whenever
disk-offload is enabled and a manifest is present, threading it through;
falls back to the pre-existing fail-close plain-drop (PR #273
policy-aware discipline — noeviction still OOMs, an evicting policy still
frees RAM) when no durability backstop exists, matching the documented
"spill is inert without one" rule.

Deterministic regression tests (no server process, no timing race):
  - storage::eviction::tests::sync_spill_non_string_victim_is_durably_spilled_not_plain_dropped
  - shard::timers::tests::test_run_eviction_spills_collection_victim_when_spill_context_given

tests/cold_collection_visibility.rs is unmodified (its GHOST assertions
are the correctness gate this fix satisfies) and green 10/10 locally on
both runtimes (monoio release-fast + tokio jemalloc release-fast).

Gates: cargo fmt --check clean; cargo clippy -- -D warnings clean (default
+ --no-default-features --features runtime-tokio,jemalloc); storage::eviction,
shard::timers, shard::persistence_tick, storage::db_quota, storage::tiered
lib test modules green.

footer: closes task #45
author: Tin Dang
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 629c76a9-9811-4336-9614-11e2045f34e9

📥 Commits

Reviewing files that changed from the base of the PR and between 7fe6884 and f4fc924.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • src/shard/persistence_tick.rs
  • src/shard/timers.rs
  • src/storage/eviction.rs

📝 Walkthrough

Walkthrough

Eviction now durably spills collection victims when a SpillContext is available, registers successful spills in ColdIndex, and retains hot values when spill I/O fails. Periodic eviction ticks construct and pass spill context when disk offload and a manifest are available.

Changes

Eviction spill behavior

Layer / File(s) Summary
Collection spill and cold-index registration
src/storage/eviction.rs
evict_one_with_spill spills all value types, fails closed on spill errors, registers successful spills in ColdIndex, and updates regression tests.
Periodic eviction spill context
src/shard/timers.rs, src/shard/persistence_tick.rs, CHANGELOG.md
Eviction APIs accept and forward optional spill context; run_eviction_tick constructs it for configured disk offload and updated tests cover tick-path spilling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant run_eviction_tick
  participant run_eviction
  participant evict_one_with_spill
  participant ColdIndex
  run_eviction_tick->>run_eviction: pass SpillContext when configured
  run_eviction->>evict_one_with_spill: forward SpillContext
  evict_one_with_spill->>ColdIndex: register successful spill
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: tick-path eviction now spills collections instead of plain-dropping them.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tick-eviction-spill

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pilotspacex-byte pilotspacex-byte merged commit 2482742 into main Jul 13, 2026
8 checks passed
@TinDang97 TinDang97 deleted the fix/tick-eviction-spill branch July 13, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants