From ec38418d6d3eb4342363af1714f0073a74d52fbc Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 28 Jun 2026 03:53:24 -0400 Subject: fix: always evict at least one cache entry when over max wttrin--cleanup-cache-if-needed removed floor(count * 0.20) entries, which is 0 for a small cache (e.g. two entries at max one), so the cache could sit over its advertised maximum indefinitely. It now removes at least one whenever it is over. --- tests/test-wttrin--cleanup-cache-if-needed.el | 9 +++++---- wttrin.el | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/test-wttrin--cleanup-cache-if-needed.el b/tests/test-wttrin--cleanup-cache-if-needed.el index 1850d17..7533bfa 100644 --- a/tests/test-wttrin--cleanup-cache-if-needed.el +++ b/tests/test-wttrin--cleanup-cache-if-needed.el @@ -108,16 +108,17 @@ (should (= 1 (testutil-wttrin-cache-size)))) (test-wttrin--cleanup-cache-if-needed-teardown))) -(ert-deftest test-wttrin--cleanup-cache-if-needed-boundary-two-entries-at-max-one-removes-none () - "Test that two entries at max=1 removes no entries due to integer division." +(ert-deftest test-wttrin--cleanup-cache-if-needed-boundary-two-entries-at-max-one-reduces-to-max () + "Boundary: two entries at max=1 reduces to the max. +floor(2 * 0.20) is 0, but cleanup must still remove at least one entry when the +cache is over max, or it would exceed its advertised maximum indefinitely." (test-wttrin--cleanup-cache-if-needed-setup) (unwind-protect (testutil-wttrin-with-cache-max 1 (testutil-wttrin-add-to-cache "old" "data1" 100) (testutil-wttrin-add-to-cache "new" "data2" 50) (wttrin--cleanup-cache-if-needed) - ;; 2 entries / 5 = 0 in integer division, so no entries removed - (should (= 2 (testutil-wttrin-cache-size)))) + (should (= 1 (testutil-wttrin-cache-size)))) (test-wttrin--cleanup-cache-if-needed-teardown))) (ert-deftest test-wttrin--cleanup-cache-if-needed-boundary-one-over-max-removes-oldest () diff --git a/wttrin.el b/wttrin.el index cdef10a..4bc1b3a 100644 --- a/wttrin.el +++ b/wttrin.el @@ -1283,12 +1283,13 @@ Returns a list where each element is a cons cell (key . timestamp)." (defun wttrin--cleanup-cache-if-needed () "Remove oldest entries if cache exceeds max size. Removes oldest entries based on `wttrin--cache-cleanup-percentage' -when cache count exceeds `wttrin-cache-max-entries'. +when cache count exceeds `wttrin-cache-max-entries', and always at least one +so the cache can't sit over its maximum when the percentage floors to zero. This creates headroom to avoid frequent cleanups." (when (> (hash-table-count wttrin--cache) wttrin-cache-max-entries) (let* ((entries-by-age (wttrin--get-cache-entries-by-age)) - (num-to-remove (floor (* (length entries-by-age) - wttrin--cache-cleanup-percentage)))) + (num-to-remove (max 1 (floor (* (length entries-by-age) + wttrin--cache-cleanup-percentage))))) (dotimes (i num-to-remove) (remhash (car (nth i entries-by-age)) wttrin--cache))))) -- cgit v1.2.3