]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Optimize] Add rspamd_heap_push_slot to eliminate double allocation
authorVsevolod Stakhov <vsevolod@rspamd.com>
Tue, 21 Oct 2025 10:34:58 +0000 (11:34 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Tue, 21 Oct 2025 10:34:58 +0000 (11:34 +0100)
Add rspamd_heap_push_slot() macro that allocates a slot directly in
the heap and returns a pointer to it, avoiding unnecessary copying.

Previously, memory pool destructors were allocated twice:
1. First allocated in mempool via rspamd_mempool_alloc_
2. Then copied into heap via rspamd_heap_push_safe

New approach:
- rspamd_heap_push_slot allocates zero-initialized slot in heap
- Returns pointer to the slot for direct filling
- User calls rspamd_heap_swim after filling to restore heap property

Benefits:
- Eliminates duplicate allocation of destructor structures
- Reduces memory usage (no temporary allocation in mempool)
- Better cache locality (destructor lives only in heap)
- Same pattern can be used elsewhere for efficient heap usage

Updated rspamd_mempool_add_destructor_full to use new API.

src/libutil/heap.h
src/libutil/mem_pool.c

index 50a2222866338f78d583d297dbc8841c86152a0f..08ed4afab37123f960f9ce0f8b87c573f0cda552 100644 (file)
@@ -153,6 +153,22 @@ extern "C" {
                }                                                            \
        } while (0)
 
+/**
+ * Allocate slot in heap and return pointer to it (zero-initialized)
+ * User fills the slot, then must call rspamd_heap_swim to restore heap property
+ * Returns NULL on allocation failure
+ */
+#define rspamd_heap_push_slot(name, heap)                                           \
+       ({                                                                              \
+               typeof(&kv_A(*(heap), 0)) slot = NULL;                                      \
+               kv_push(typeof(kv_A(*(heap), 0)), *(heap), (typeof(kv_A(*(heap), 0))) {0}); \
+               if (kv_size(*(heap)) > 0) {                                                 \
+                       slot = &kv_A(*(heap), kv_size(*(heap)) - 1);                            \
+                       slot->idx = kv_size(*(heap)) - 1;                                       \
+               }                                                                           \
+               slot;                                                                       \
+       })
+
 /**
  * Push element to heap (safe version with error handling)
  * Element is copied into the heap array.
index d806a34e23070b664f19ce0c8ff480805881ec6e..b7441ee4bc988bc90d90bf4398d52e6f1600859e 100644 (file)
@@ -670,15 +670,6 @@ void rspamd_mempool_add_destructor_full(rspamd_mempool_t *pool,
 
        POOL_MTX_LOCK();
 
-       /* Allocate destructor structure */
-       dtor = rspamd_mempool_alloc_(pool, sizeof(*dtor),
-                                                                RSPAMD_ALIGNOF(struct _pool_destructors), line);
-       dtor->func = func;
-       dtor->data = data;
-       dtor->function = function;
-       dtor->loc = line;
-       dtor->pri = priority;
-
        /* Initialize heap if not yet created */
        if (pool->priv->dtors_heap.a == NULL) {
                rspamd_heap_init(rspamd_mempool_destruct_heap, &pool->priv->dtors_heap);
@@ -690,8 +681,21 @@ void rspamd_mempool_add_destructor_full(rspamd_mempool_t *pool,
                }
        }
 
-       /* Push to heap - using non-safe version as we're in mempool */
-       rspamd_heap_push_safe(rspamd_mempool_destruct_heap, &pool->priv->dtors_heap, dtor, cleanup);
+       /* Allocate slot directly in heap (avoids double allocation) */
+       dtor = rspamd_heap_push_slot(rspamd_mempool_destruct_heap, &pool->priv->dtors_heap);
+       if (dtor == NULL) {
+               goto cleanup;
+       }
+
+       /* Fill destructor structure */
+       dtor->func = func;
+       dtor->data = data;
+       dtor->function = function;
+       dtor->loc = line;
+       dtor->pri = priority;
+
+       /* Restore heap property after filling the slot */
+       rspamd_heap_swim(rspamd_mempool_destruct_heap, &pool->priv->dtors_heap, dtor);
 
        POOL_MTX_UNLOCK();
        return;