Fix LRU RAM cache seen filter never engaging below 100% full#13234
Fix LRU RAM cache seen filter never engaging below 100% full#13234phongn wants to merge 1 commit into
Conversation
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>
There was a problem hiding this comment.
Pull request overview
This PR fixes the LRU RAM cache “seen filter” engagement threshold so that proxy.config.cache.ram_cache.use_seen_filter values 2–9 activate the filter at the documented partial-fill levels (instead of only at 100% due to integer division). It also adds a regression test to ensure the filter engages once the cache is above the configured threshold.
Changes:
- Replace the integer-division-based seen-filter threshold check with an equivalent integer-arithmetic comparison.
- Add a nightly regression test validating that the tiered LRU seen filter begins rejecting single-seen inserts above the configured fill threshold.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/iocore/cache/RamCacheLRU.cc |
Fixes the seen-filter engagement condition for use_seen_filter > 1 to match documented behavior. |
src/iocore/cache/CacheTest.cc |
Adds a nightly regression test to verify the LRU seen filter engages at the intended cache fill level. |
| if ((cache_config_ram_cache_use_seen_filter == 1) || | ||
| // If proxy.config.cache.ram_cache.use_seen_filter is > 1, and the cache is more than <n>% full, then use the seen filter. | ||
| // <n>% is calculated based on this setting, with 2 == 50%, 3 == 67%, 4 == 75%, up to 9 == 90%. | ||
| ((cache_config_ram_cache_use_seen_filter > 1) && (bytes >= max_bytes * (1 - (1 / cache_config_ram_cache_use_seen_filter))))) { | ||
| // For use_seen_filter > 1, only apply the filter once the cache is more than <n>% full: | ||
| // 2 == 50%, 3 == 67%, 4 == 75%, up to 9 == 90%. Written as bytes * N >= max_bytes * (N - 1) | ||
| // rather than bytes >= max_bytes * (1 - 1 / N); the latter evaluates 1 / N in integer | ||
| // arithmetic (0 for every N > 1), so the filter only ever engaged at 100% full. | ||
| ((cache_config_ram_cache_use_seen_filter > 1) && | ||
| (bytes * cache_config_ram_cache_use_seen_filter >= max_bytes * (cache_config_ram_cache_use_seen_filter - 1)))) { |
There was a problem hiding this comment.
I will update the configuration parser for proxy.config.cache.ram_cache.use_seen_filter to only allow integer values 0-9 when using LRU in a separate PR, and also to only allow values 0-1 for CLFUS.
At the moment nobody should be using sufficiently large values to cause integer overflow.
|
@moonchen Can you determine how big of an issue this is and if we should backport it to 10.1.x or 10.2.x? |
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_filtergreater than 1 is documented to enable the seen filter once the cache is more than n% full (2= 50%,3= 67%,4= 75%, up to9= 90%). The check was:cache_config_ram_cache_use_seen_filteris anint, so1 / Nis integer division and is0for everyN > 1. The expression collapses tobytes >= 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: withuse_seen_filter = 2, fill the cache to ~60% thenPut20 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 existingram_cacheregression test still passes.Impact
Operators who set
use_seen_filterto 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).