From: Willy Tarreau Date: Wed, 8 Nov 2023 15:35:49 +0000 (+0100) Subject: BUG/MEDIUM: pool: fix releasable pool calculation when overloaded X-Git-Tag: v2.9-dev10~136 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89c6b67a8241cdc56b42ecea52983e632f00b3bc;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/include/haproxy/pool.h b/include/haproxy/pool.h index 5375b35c91..bf7cb8d012 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))