]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: pools: centralize cache eviction in a common function
authorWilly Tarreau <w@1wt.eu>
Sun, 2 Jan 2022 16:19:14 +0000 (17:19 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 2 Jan 2022 18:35:26 +0000 (19:35 +0100)
We currently have two functions to evict cold objects from local caches:
pool_evict_from_local_cache() to evict from a single cache, and
pool_evict_from_local_caches() to evict oldest objects from all caches.

The new function pool_evict_last_items() focuses on scanning oldest
objects from a pool and releasing a predefined number of them, either
to the shared pool or to the system. For now they're evicted one at a
time, but the next step will consist in creating clusters.

src/pool.c

index 2257dc9f49971f70d5d606513183e92d68b37258..2a56cd4dc50f547ae4028f2556d910002c261d6f 100644 (file)
@@ -301,44 +301,54 @@ void pool_free_nocache(struct pool_head *pool, void *ptr)
 
 #ifdef CONFIG_HAP_POOLS
 
-/* Evicts some of the oldest objects from one local cache, until its number of
- * objects is no more than 16+1/8 of the total number of locally cached objects
- * or the total size of the local cache is no more than 75% of its maximum (i.e.
- * we don't want a single cache to use all the cache for itself). For this, the
- * list is scanned in reverse.
+/* removes up to <count> items from the end of the local pool cache <ph> for
+ * pool <pool>. The shared pool is refilled with these objects in the limit
+ * of the number of acceptable objects, and the rest will be released to the
+ * OS. It is not a problem is <count> is larger than the number of objects in
+ * the local cache. The counters are automatically updated.
  */
-void pool_evict_from_local_cache(struct pool_head *pool)
+static void pool_evict_last_items(struct pool_head *pool, struct pool_cache_head *ph, uint count)
 {
-       struct pool_cache_head *ph = &pool->cache[tid];
-       struct pool_item *pi, *to_free = NULL;
        struct pool_cache_item *item;
+       struct pool_item *pi;
+       uint released = 0;
        uint to_free_max;
 
        to_free_max = pool_releasable(pool);
 
-       while (ph->count >= 16 + pool_cache_count / 8 &&
-              pool_cache_bytes > CONFIG_HAP_POOL_CACHE_SIZE * 3 / 4) {
+       while (released < count && !LIST_ISEMPTY(&ph->list)) {
                item = LIST_PREV(&ph->list, typeof(item), by_pool);
-               ph->count--;
-               pool_cache_bytes -= pool->size;
-               pool_cache_count--;
                LIST_DELETE(&item->by_pool);
                LIST_DELETE(&item->by_lru);
+               released++;
 
                if (to_free_max) {
                        pi = (struct pool_item *)item;
-                       pi->next = to_free;
-                       to_free = pi;
+                       pi->down = NULL;
+                       pool_put_to_shared_cache(pool, pi, 1);
                        to_free_max--;
                } else
                        pool_free_nocache(pool, item);
        }
 
-       while (to_free) {
-               pi = to_free;
-               pi->down = NULL;
-               to_free = pi->next;
-               pool_put_to_shared_cache(pool, pi, 1);
+       ph->count -= released;
+       pool_cache_count -= released;
+       pool_cache_bytes -= released * pool->size;
+}
+
+/* Evicts some of the oldest objects from one local cache, until its number of
+ * objects is no more than 16+1/8 of the total number of locally cached objects
+ * or the total size of the local cache is no more than 75% of its maximum (i.e.
+ * we don't want a single cache to use all the cache for itself). For this, the
+ * list is scanned in reverse.
+ */
+void pool_evict_from_local_cache(struct pool_head *pool)
+{
+       struct pool_cache_head *ph = &pool->cache[tid];
+
+       while (ph->count >= 16 + pool_cache_count / 8 &&
+              pool_cache_bytes > CONFIG_HAP_POOL_CACHE_SIZE * 3 / 4) {
+               pool_evict_last_items(pool, ph, 1);
        }
 }
 
@@ -358,19 +368,7 @@ void pool_evict_from_local_caches()
                 */
                ph = LIST_NEXT(&item->by_pool, struct pool_cache_head *, list);
                pool = container_of(ph - tid, struct pool_head, cache);
-               LIST_DELETE(&item->by_pool);
-               LIST_DELETE(&item->by_lru);
-               ph->count--;
-               pool_cache_count--;
-               pool_cache_bytes -= pool->size;
-               if (unlikely(pool_is_crowded(pool)))
-                       pool_free_nocache(pool, item);
-               else {
-                       struct pool_item *pi = (struct pool_item *)item;
-
-                       pi->down = NULL;
-                       pool_put_to_shared_cache(pool, pi, 1);
-               }
+               pool_evict_last_items(pool, ph, 1);
        } while (pool_cache_bytes > CONFIG_HAP_POOL_CACHE_SIZE * 7 / 8);
 }