MINOR: pools: prepare pool_item to support chained clusters
In order to support batched allocations and releases, we'll need to
prepare chains of items linked together and that can be atomically
attached and detached at once. For this we implement a "down" pointer
in each pool_item that points to the other items belonging to the same
group. For now it's always NULL though freeing functions already check
them when trying to release everything.
diff --git a/include/haproxy/pool-t.h b/include/haproxy/pool-t.h
index 29adf65..f6b74e3 100644
--- a/include/haproxy/pool-t.h
+++ b/include/haproxy/pool-t.h
@@ -60,10 +60,29 @@
};
/* This structure is used to represent an element in the pool's shared
- * free_list.
+ * free_list. An item may carry a series of other items allocated or released
+ * as a same cluster. The storage then looks like this:
+ * +------+ +------+ +------+
+ * -->| next |-->| next |-->| NULL |
+ * +------+ +------+ +------+
+ * | NULL | | down | | down |
+ * +------+ +--|---+ +--|---+
+ * V V
+ * +------+ +------+
+ * | NULL | | NULL |
+ * +------+ +------+
+ * | down | | NULL |
+ * +--|---+ +------+
+ * V
+ * +------+
+ * | NULL |
+ * +------+
+ * | NULL |
+ * +------+
*/
struct pool_item {
struct pool_item *next;
+ struct pool_item *down; // link to other items of the same cluster
};
/* This describes a complete pool, with its status, usage statistics and the
diff --git a/src/pool.c b/src/pool.c
index 6ea081e..68e83aa 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -336,6 +336,7 @@
while (to_free) {
pi = to_free;
+ pi->down = NULL;
to_free = pi->next;
pool_put_to_shared_cache(pool, pi);
}
@@ -364,8 +365,12 @@
pool_cache_bytes -= pool->size;
if (unlikely(pool_is_crowded(pool)))
pool_free_nocache(pool, item);
- else
- pool_put_to_shared_cache(pool, (struct pool_item *)item);
+ else {
+ struct pool_item *pi = (struct pool_item *)item;
+
+ pi->down = NULL;
+ pool_put_to_shared_cache(pool, pi);
+ }
} while (pool_cache_bytes > CONFIG_HAP_POOL_CACHE_SIZE * 7 / 8);
}
@@ -417,7 +422,8 @@
void pool_refill_local_from_shared(struct pool_head *pool, struct pool_cache_head *pch)
{
struct pool_cache_item *item;
- struct pool_item *ret;
+ struct pool_item *ret, *down;
+ uint count;
/* we'll need to reference the first element to figure the next one. We
* must temporarily lock it so that nobody allocates then releases it,
@@ -440,18 +446,23 @@
/* this releases the lock */
HA_ATOMIC_STORE(&pool->free_list, ret->next);
- HA_ATOMIC_INC(&pool->used);
- /* keep track of where the element was allocated from */
- POOL_DEBUG_SET_MARK(pool, ret);
+ /* now store the retrieved object(s) into the local cache */
+ count = 0;
+ for (; ret; ret = down) {
+ down = ret->down;
+ /* keep track of where the element was allocated from */
+ POOL_DEBUG_SET_MARK(pool, ret);
- /* now store the retrieved object into the local cache */
- item = (struct pool_cache_item *)ret;
- LIST_INSERT(&pch->list, &item->by_pool);
- LIST_INSERT(&th_ctx->pool_lru_head, &item->by_lru);
- pch->count++;
- pool_cache_count++;
- pool_cache_bytes += pool->size;
+ item = (struct pool_cache_item *)ret;
+ LIST_INSERT(&pch->list, &item->by_pool);
+ LIST_INSERT(&th_ctx->pool_lru_head, &item->by_lru);
+ count++;
+ }
+ HA_ATOMIC_ADD(&pool->used, count);
+ pch->count += count;
+ pool_cache_count += count;
+ pool_cache_bytes += count * pool->size;
}
/* Adds cache item entry <item> to the shared cache. The caller is advised to
@@ -482,7 +493,7 @@
*/
void pool_flush(struct pool_head *pool)
{
- struct pool_item *next, *temp;
+ struct pool_item *next, *temp, *down;
if (!pool)
return;
@@ -505,7 +516,10 @@
while (next) {
temp = next;
next = temp->next;
- pool_put_to_os(pool, temp);
+ for (; temp; temp = down) {
+ down = temp->down;
+ pool_put_to_os(pool, temp);
+ }
}
/* here, we should have pool->allocated == pool->used */
}
@@ -524,13 +538,16 @@
thread_isolate();
list_for_each_entry(entry, &pools, list) {
- struct pool_item *temp;
+ struct pool_item *temp, *down;
while (entry->free_list &&
(int)(entry->allocated - entry->used) > (int)entry->minavail) {
temp = entry->free_list;
entry->free_list = temp->next;
- pool_put_to_os(entry, temp);
+ for (; temp; temp = down) {
+ down = temp->down;
+ pool_put_to_os(entry, temp);
+ }
}
}