Skip to content

Fix LRU RAM cache seen filter never engaging below 100% full#13234

Open
phongn wants to merge 1 commit into
apache:masterfrom
phongn:fix-lru-seen-filter-threshold
Open

Fix LRU RAM cache seen filter never engaging below 100% full#13234
phongn wants to merge 1 commit into
apache:masterfrom
phongn:fix-lru-seen-filter-threshold

Conversation

@phongn
Copy link
Copy Markdown
Collaborator

@phongn phongn commented Jun 3, 2026

Summary

The tiered seen filter for the (default) LRU RAM cache never engaged at the documented fill levels: an integer-division bug made it engage only when the cache was 100% full, so a scan could pollute a partly-full cache.

Root cause

proxy.config.cache.ram_cache.use_seen_filter greater than 1 is documented to enable the seen filter once the cache is more than n% full (2 = 50%, 3 = 67%, 4 = 75%, up to 9 = 90%). The check was:

(bytes >= max_bytes * (1 - (1 / cache_config_ram_cache_use_seen_filter)))

cache_config_ram_cache_use_seen_filter is an int, so 1 / N is integer division and is 0 for every N > 1. The expression collapses to bytes >= max_bytes, i.e. the filter engages only at 100% full, and values 2–9 all behave identically.

Fix

Rewrite the comparison so it is exact in integer arithmetic and overflow-safe at realistic cache sizes:

(bytes * cache_config_ram_cache_use_seen_filter >= max_bytes * (cache_config_ram_cache_use_seen_filter - 1))

N=2 → ≥50%, N=3 → ≥67%, N=9 → ≥89%, as documented. (Only the LRU RAM cache uses the tiered percentage; CLFUS treats the knob as on/off and is unaffected.)

Test

Adds ram_cache_lru_seen_filter: with use_seen_filter = 2, fill the cache to ~60% then Put 20 unseen keys once each — above the 50% threshold the filter must reject them. Verified it fails on the old form (20/20 admitted at 60% full) and passes on the fix (0/20). The existing ram_cache regression test still passes.

Impact

Operators who set use_seen_filter to 2–9 to get scan resistance once the cache is partly full currently get none until it is completely full. This affects the default RAM cache (LRU).

proxy.config.cache.ram_cache.use_seen_filter values above 1 are
documented to turn on the seen filter once the cache is (N-1)/N full
(2 = 50%, 3 = 67%, ... 9 = 90%). The threshold was written as
bytes >= max_bytes * (1 - (1 / N)) with N an int, so 1 / N is integer
division and evaluates to 0 for every N > 1; the test became
bytes >= max_bytes and the filter only engaged when completely full.
A scan could therefore pollute a half-full cache.

Rewrite the comparison as bytes * N >= max_bytes * (N - 1), which is
exact in integer arithmetic and overflow-safe at realistic cache
sizes. Add ram_cache_lru_seen_filter, which fails on the old form
(20/20 unseen keys admitted at 60% full) and passes on the fix (0/20).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant