From 89c6b67a8241cdc56b42ecea52983e632f00b3bc Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 8 Nov 2023 16:35:49 +0100 Subject: [PATCH] BUG/MEDIUM: pool: fix releasable pool calculation when overloaded In 2.6-dev1, the method used to decide how many pool entries could be released at once was revisited to support releases in batches. This was done with commits 91a8e28f9 ("MINOR: pool: add a function to estimate how many may be released at once") and 361e31e3f ("MEDIUM: pool: compute the number of evictable entries once per pool"). The first commit takes care of the possible inconsistency between the moment the allocated count and the used count are read, but unfortunately fixed it the wrong way, by adjusting "used" to match "alloc" whenever it was lower (i.e. almost always). This results in a nasty case which is that as soon as the allocated value becomes higher than the estimated count of needed entries, we end up returning pool->minavail, which causes very small batches to be released, starting from commit 1513c5479 ("MEDIUM: pools: release cached objects in batches"). The problem was further amplified in 2.9-dev3 with commit 7bf829ace ("MAJOR: pools: move the shared pool's free_list over multiple buckets") because it now becomes possible for a thread to allocate from one bucket and release into a few other different ones, causing an accumulation of entries in that bucket. The fix is trivial, simply adjust the alloc counter if the used one is higher, before performing operations. This must be backported to 2.6. --- include/haproxy/pool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/haproxy/pool.h b/include/haproxy/pool.h index 5375b35c9..bf7cb8d01 100644 --- a/include/haproxy/pool.h +++ b/include/haproxy/pool.h @@ -208,8 +208,8 @@ static inline uint pool_releasable(const struct pool_head *pool) alloc = pool_allocated(pool); used = pool_used(pool); - if (used < alloc) - used = alloc; + if (used > alloc) + alloc = used; needed_raw = pool_needed_avg(pool); if (alloc < swrate_avg(needed_raw + needed_raw / 4, POOL_AVG_SAMPLES))