]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Remove one layer of heap derefs and shrink heaps as elements are removed
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 31 Mar 2022 16:12:05 +0000 (10:12 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 31 Mar 2022 16:12:18 +0000 (10:12 -0600)
15 files changed:
src/lib/io/master.c
src/lib/io/network.c
src/lib/io/worker.c
src/lib/server/cf_file.c
src/lib/server/pool.c
src/lib/server/trunk.c
src/lib/unlang/interpret_synchronous.c
src/lib/unlang/xlat_inst.c
src/lib/util/heap.c
src/lib/util/heap.h
src/lib/util/heap_tests.c
src/lib/util/lst_tests.c
src/lib/util/minmax_heap_tests.c
src/modules/proto_ldap_sync/proto_ldap_sync.c
src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c

index 0bf9324d04eecdd49fda11be7e983fdc59c9c4f6..e802e5f3ac276fa827831d33a66b80cef681d463 100644 (file)
@@ -320,7 +320,7 @@ static fr_io_pending_packet_t *pending_packet_pop(fr_io_thread_t *thread)
        fr_io_client_t *client;
        fr_io_pending_packet_t *pending;
 
-       client = fr_heap_pop(thread->pending_clients);
+       client = fr_heap_pop(&thread->pending_clients);
        if (!client) {
                /*
                 *      99% of the time we don't have pending clients.
@@ -332,7 +332,7 @@ static fr_io_pending_packet_t *pending_packet_pop(fr_io_thread_t *thread)
                return NULL;
        }
 
-       pending = fr_heap_pop(client->pending);
+       pending = fr_heap_pop(&client->pending);
        fr_assert(pending != NULL);
 
        /*
@@ -340,7 +340,7 @@ static fr_io_pending_packet_t *pending_packet_pop(fr_io_thread_t *thread)
         *      the heap.
         */
        if (fr_heap_num_elements(client->pending) > 0) {
-               if (fr_heap_insert(thread->pending_clients, client) < 0) {
+               if (fr_heap_insert(&thread->pending_clients, client) < 0) {
                        fr_assert(0 == 1);
                }
        }
@@ -1047,7 +1047,7 @@ static fr_io_pending_packet_t *fr_io_pending_alloc(fr_io_client_t *client,
         *      Insert the pending packet for this client.  If it
         *      fails, silently discard the packet.
         */
-       if (fr_heap_insert(client->pending, pending) < 0) {
+       if (fr_heap_insert(&client->pending, pending) < 0) {
                talloc_free(pending);
                return NULL;
        }
@@ -1094,7 +1094,7 @@ static int _client_live_free(fr_io_client_t *client)
        if (client->pending) TALLOC_FREE(client->pending);
 
        (void) fr_trie_remove_by_key(client->thread->trie, &client->src_ipaddr.addr, client->src_ipaddr.prefix);
-       (void) fr_heap_extract(client->thread->alive_clients, client);
+       (void) fr_heap_extract(&client->thread->alive_clients, client);
 
        return 0;
 }
@@ -1150,7 +1150,7 @@ redo:
                        return -1;
                }
 
-               pending = fr_heap_pop(connection->client->pending);
+               pending = fr_heap_pop(&connection->client->pending);
 
        } else if (thread->pending_clients) {
                pending = pending_packet_pop(thread);
@@ -1510,7 +1510,7 @@ do_read:
                 *      Track the live clients so that we can clean
                 *      them up.
                 */
-               (void) fr_heap_insert(thread->alive_clients, client);
+               (void) fr_heap_insert(&thread->alive_clients, client);
                client->pending_id = -1;
 
                /*
@@ -2485,7 +2485,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, fr_time_t request_ti
        }
 
        fr_assert(client->pending_id < 0);
-       (void) fr_heap_insert(thread->pending_clients, client);
+       (void) fr_heap_insert(&thread->pending_clients, client);
 
 finish:
        /*
index f6eb65ea2ff0b7cbf49525b316c53a1caaebc172..657d9bd2fa66d184b16eaf370ae233141d0d0644 100644 (file)
@@ -364,7 +364,7 @@ void fr_network_listen_write(fr_network_t *nr, fr_listen_t *li, uint8_t const *p
        lm = fr_message_localize(nr, &cd.m, sizeof(cd));
        if (!lm) return;
 
-       if (fr_heap_insert(nr->replies, lm) < 0) {
+       if (fr_heap_insert(&nr->replies, lm) < 0) {
                fr_message_done(lm);
        }
 }
@@ -484,7 +484,7 @@ static void fr_network_recv_reply(void *ctx, fr_channel_t *ch, fr_channel_data_t
         *      Ensure that heap insert works.
         */
        cd->channel.heap_id = 0;
-       if (fr_heap_insert(nr->replies, cd) < 0) {
+       if (fr_heap_insert(&nr->replies, cd) < 0) {
                fr_message_done(&cd->m);
                fr_assert(0 == 1);
        }
@@ -1004,7 +1004,7 @@ static void fr_network_write(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUS
                s->pending = NULL;
 
        } else {
-               cd = fr_heap_pop(s->waiting);
+               cd = fr_heap_pop(&s->waiting);
        }
 
        while (cd != NULL) {
@@ -1096,7 +1096,7 @@ static void fr_network_write(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUS
                /*
                 *      Grab the net entry.
                 */
-               cd = fr_heap_pop(s->waiting);
+               cd = fr_heap_pop(&s->waiting);
        }
 
        /*
@@ -1135,7 +1135,7 @@ static int _network_socket_free(fr_network_socket_t *s)
        /*
         *      Clean up any queued entries.
         */
-       while ((cd = fr_heap_pop(s->waiting)) != NULL) {
+       while ((cd = fr_heap_pop(&s->waiting)) != NULL) {
                fr_message_done(&cd->m);
        }
 
@@ -1452,7 +1452,7 @@ static void fr_network_post_event(UNUSED fr_event_list_t *el, UNUSED fr_time_t n
         *      Pull the replies off of our global heap, and try to
         *      push them to the individual sockets.
         */
-       while ((cd = fr_heap_pop(nr->replies)) != NULL) {
+       while ((cd = fr_heap_pop(&nr->replies)) != NULL) {
                fr_listen_t *li;
                fr_network_socket_t *s;
 
@@ -1508,7 +1508,7 @@ static void fr_network_post_event(UNUSED fr_event_list_t *el, UNUSED fr_time_t n
                 */
                if (!s->pending) {
                        fr_assert(!s->blocked);
-                       (void) fr_heap_insert(s->waiting, cd);
+                       (void) fr_heap_insert(&s->waiting, cd);
                        fr_network_write(nr->el, s->listen->fd, 0, s);
                }
        }
@@ -1559,7 +1559,7 @@ int fr_network_destroy(fr_network_t *nr)
         *      @todo - call transport "done" for the reply, so that
         *      it knows the replies are done, too.
         */
-       while ((cd = fr_heap_pop(nr->replies)) != NULL) {
+       while ((cd = fr_heap_pop(&nr->replies)) != NULL) {
                fr_message_done(&cd->m);
        }
 
index f4d6315a0b08912695dcd994660b63de074f64a9..a5de9fc2fcf03930b6fd486eb62be4c6e6dda45a 100644 (file)
@@ -472,7 +472,7 @@ static void worker_request_time_tracking_start(fr_worker_t *worker, request_t *r
        worker->num_active++;
 
        fr_assert(!fr_heap_entry_inserted(request->runnable_id));
-       (void) fr_heap_insert(worker->runnable, request);
+       (void) fr_heap_insert(&worker->runnable, request);
 
        if (!worker->ev_cleanup) worker_max_request_timer(worker);
 }
@@ -1094,7 +1094,7 @@ static void _worker_request_stop(request_t *request, void *uctx)
         *      yank it back out, so it's not "runnable"
         *      when we call request done.
         */
-       if (fr_heap_entry_inserted(request->runnable_id)) fr_heap_extract(worker->runnable, request);
+       if (fr_heap_entry_inserted(request->runnable_id)) fr_heap_extract(&worker->runnable, request);
 
        /*
         *      The interpreter doesn't currently fix
@@ -1112,7 +1112,7 @@ static void _worker_request_runnable(request_t *request, void *uctx)
        fr_worker_t     *worker = uctx;
 
        RDEBUG3("Request marked as runnable");
-       fr_heap_insert(worker->runnable, request);
+       fr_heap_insert(&worker->runnable, request);
 }
 
 /** Interpreter yielded request
@@ -1167,7 +1167,7 @@ static inline CC_HINT(always_inline) void worker_run_request(fr_worker_t *worker
         *      every request.
         */
        while (fr_time_delta_lt(fr_time_sub(now, start), fr_time_delta_wrap(NSEC / 100000)) &&
-              ((request = fr_heap_pop(worker->runnable)) != NULL)) {
+              ((request = fr_heap_pop(&worker->runnable)) != NULL)) {
 
                REQUEST_VERIFY(request);
                fr_assert(!fr_heap_entry_inserted(request->runnable_id));
index 8ffbbd0bdc1fc4ef69dcacfca9b04f6ab232056f..a482fe303ebf43a58570fc9e2ccc128065d49bdd 100644 (file)
@@ -1073,7 +1073,7 @@ static int process_include(cf_stack_t *stack, CONF_SECTION *parent, char const *
                        MEM(h = talloc_zero(frame->heap, cf_file_heap_t));
                        MEM(h->filename = talloc_typed_strdup(h, stack->buff[1]));
                        h->heap_id = 0;
-                       (void) fr_heap_insert(frame->heap, h);
+                       (void) fr_heap_insert(&frame->heap, h);
                }
                closedir(dir);
 
@@ -2029,7 +2029,7 @@ static int frame_readdir(cf_stack_t *stack)
        CONF_SECTION *parent = frame->current;
        cf_file_heap_t *h;
 
-       h = fr_heap_pop(frame->heap);
+       h = fr_heap_pop(&frame->heap);
        if (!h) {
                /*
                 *      Done reading the directory entry.  Close it, and go
index dcf244f7ece5f73dca761d0059ef11e9b51a43d2..3a2b8aa9663dcb42f818c6d0d56a05664800c5e8 100644 (file)
@@ -481,7 +481,7 @@ static fr_pool_connection_t *connection_spawn(fr_pool_t *pool, request_t *reques
         *      The connection pool is starting up.  Insert the
         *      connection into the heap.
         */
-       if (!in_use) fr_heap_insert(pool->heap, this);
+       if (!in_use) fr_heap_insert(&pool->heap, this);
 
        connection_link_head(pool, this);
 
@@ -553,7 +553,7 @@ static void connection_close_internal(fr_pool_t *pool, fr_pool_connection_t *thi
                /*
                 *      Connection isn't used, remove it from the heap.
                 */
-               fr_heap_extract(pool->heap, this);
+               fr_heap_extract(&pool->heap, this);
        }
 
        fr_pool_trigger_exec(pool, "close");
@@ -841,7 +841,7 @@ static void *connection_get_internal(fr_pool_t *pool, request_t *request, bool s
         *      heap and use it.
         */
        if (this) {
-               fr_heap_extract(pool->heap, this);
+               fr_heap_extract(&pool->heap, this);
                goto do_return;
        }
 
@@ -1432,7 +1432,7 @@ void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
         *      gradually expired), or when we released it (allowing
         *      the maximum amount of time between connection use).
         */
-       fr_heap_insert(pool->heap, this);
+       fr_heap_insert(&pool->heap, this);
 
        fr_assert(pool->state.active != 0);
        pool->state.active--;
index e10de819bae31d948845f1a6c24e1252ea6f0464..ef77846b7a1d3eff26bc3b676de8efbfef51eac0 100644 (file)
@@ -701,7 +701,7 @@ do { \
 #define REQUEST_EXTRACT_BACKLOG(_treq) \
 do { \
        int _ret; \
-       _ret = fr_heap_extract((_treq)->pub.trunk->backlog, _treq); \
+       _ret = fr_heap_extract(&(_treq)->pub.trunk->backlog, _treq); \
        if (!fr_cond_assert_msg(_ret == 0, "Failed extracting conn from backlog heap: %s", fr_strerror())) break; \
 } while (0)
 
@@ -711,7 +711,7 @@ do { \
 #define REQUEST_EXTRACT_PENDING(_treq) \
 do { \
        int _ret; \
-       _ret = fr_heap_extract((_treq)->pub.tconn->pending, _treq); \
+       _ret = fr_heap_extract(&(_treq)->pub.tconn->pending, _treq); \
        if (!fr_cond_assert_msg(_ret == 0, "Failed extracting conn from pending heap: %s", fr_strerror())) break; \
 } while (0)
 
@@ -1086,7 +1086,7 @@ static void trunk_request_enter_backlog(fr_trunk_request_t *treq, bool new)
        }
 
        REQUEST_STATE_TRANSITION(FR_TRUNK_REQUEST_STATE_BACKLOG);
-       fr_heap_insert(trunk->backlog, treq);   /* Insert into the backlog heap */
+       fr_heap_insert(&trunk->backlog, treq);  /* Insert into the backlog heap */
 
        /*
         *      A new request has entered the trunk.
@@ -1165,7 +1165,7 @@ static void trunk_request_enter_pending(fr_trunk_request_t *treq, fr_trunk_conne
                ROPTIONAL(RDEBUG, DEBUG3, "[%" PRIu64 "] Trunk connection assigned request %"PRIu64,
                          tconn->pub.conn->id, treq->id);
        }
-       fr_heap_insert(tconn->pending, treq);
+       fr_heap_insert(&tconn->pending, treq);
 
        /*
         *      A new request has entered the trunk.
index fc9dc34640c693344c09959c25e6321623ed8850..b00320044e09bd15a637250763f5df148bb8bb34 100644 (file)
@@ -42,7 +42,7 @@ static void _request_init_internal(request_t *request, void *uctx)
 
        RDEBUG3("Initialising internal synchronous request");
        unlang_interpret_set(request, intps->intp);
-       fr_heap_insert(intps->runnable, request);
+       fr_heap_insert(&intps->runnable, request);
 }
 
 /** External request is now complete
@@ -102,7 +102,7 @@ static void _request_stop(request_t *request, void *uctx)
 
        RDEBUG3("Stopped detached request");
 
-       fr_heap_extract(intps->runnable, request);
+       fr_heap_extract(&intps->runnable, request);
 }
 
 /** Request is now runnable
@@ -112,7 +112,7 @@ static void _request_runnable(request_t *request, void *uctx)
 {
        unlang_interpret_synchronous_t  *intps = uctx;
 
-       fr_heap_insert(intps->runnable, request);
+       fr_heap_insert(&intps->runnable, request);
 }
 
 /** Interpreter yielded request
@@ -249,7 +249,7 @@ rlm_rcode_t unlang_interpret_synchronous(fr_event_list_t *el, request_t *request
                 *      request, THEN we're guaranteed that there is
                 *      still a timer event left.
                 */
-               sub_request = fr_heap_pop(intps->runnable);
+               sub_request = fr_heap_pop(&intps->runnable);
                if (!sub_request) {
                        DEBUG3("No pending requests (%u yielded)", intps->yielded);
                        continue;
index a85d1e6d35b8dc1d183e3cd21916c89b60437c3a..8c16142c55ec043f684db2b22f4370dc3898ef21 100644 (file)
@@ -189,7 +189,7 @@ static int _xlat_inst_detach(xlat_inst_t *xi)
         *      freed.
         */
        if (!call->ephemeral) {
-               if (fr_heap_entry_inserted(xi->idx)) fr_heap_extract(xlat_inst_tree, xi);
+               if (fr_heap_entry_inserted(xi->idx)) fr_heap_extract(&xlat_inst_tree, xi);
                if (fr_heap_num_elements(xlat_inst_tree) == 0) TALLOC_FREE(xlat_inst_tree);
        }
 
@@ -376,7 +376,7 @@ int xlat_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
                DEBUG3("Instantiating xlat \"%s\" node %p, instance %p, new thread instance %p",
                       call->func->name, xt->node, xi->data, xt);
 
-               ret = fr_heap_insert(xlat_thread_inst_tree, xt);
+               ret = fr_heap_insert(&xlat_thread_inst_tree, xt);
                if (!fr_cond_assert(ret == 0)) {
                error:
                        TALLOC_FREE(xlat_thread_inst_tree);     /* Reset the tree on error */
@@ -493,7 +493,7 @@ int xlat_bootstrap_func(xlat_exp_t *node)
         */
        node->call.id = call_id++;
 
-       ret = fr_heap_insert(xlat_inst_tree, call->inst);
+       ret = fr_heap_insert(&xlat_inst_tree, call->inst);
        if (!fr_cond_assert(ret == 0)) {
                TALLOC_FREE(call->inst);
                return -1;
@@ -551,5 +551,5 @@ void xlat_instances_free(void)
         *      is freed, so we need to check there's
         *      still a heap to pass to fr_heap_pop.
         */
-       while (xlat_inst_tree && (xi = fr_heap_pop(xlat_inst_tree))) talloc_free(xi);
+       while (xlat_inst_tree && (xi = fr_heap_pop(&xlat_inst_tree))) talloc_free(xi);
 }
index 4f0449e6c35a76f32321abf3b439eead72a8ac93..06622189a56250961a6ff9a827a01b0b8f114ff6 100644 (file)
 RCSID("$Id$")
 
 #define _HEAP_PRIVATE 1
+#include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/heap.h>
+#include <freeradius-devel/util/misc.h>
 #include <freeradius-devel/util/strerror.h>
-#include <freeradius-devel/util/debug.h>
 
 #define INITIAL_CAPACITY       2048
 
@@ -39,7 +40,7 @@ RCSID("$Id$")
 #define HEAP_RIGHT(_x) (2 * (_x) + 1 )
 #define        HEAP_SWAP(_a, _b) { void *_tmp = _a; _a = _b; _b = _tmp; }
 
-static void fr_heap_bubble(fr_heap_ext_t *h, fr_heap_index_t child);
+static void fr_heap_bubble(fr_heap_t *h, fr_heap_index_t child);
 
 /** Return how many bytes need to be allocated to hold a heap of a given size
  *
@@ -50,31 +51,28 @@ static void fr_heap_bubble(fr_heap_ext_t *h, fr_heap_index_t child);
  */
 size_t fr_heap_pre_alloc_size(unsigned int count)
 {
-       return sizeof(fr_heap_t) + sizeof(fr_heap_ext_t) + sizeof(void *) * count;
+       return sizeof(fr_heap_t) + sizeof(void *) * count;
 }
 
 fr_heap_t *_fr_heap_alloc(TALLOC_CTX *ctx, fr_heap_cmp_t cmp, char const *type, size_t offset, unsigned int init)
 {
-       fr_heap_t *hp;
-       fr_heap_ext_t *h;
+       fr_heap_t *h;
 
        if (!init) init = INITIAL_CAPACITY;
 
-       hp = talloc(ctx, fr_heap_t);
-       if (unlikely(!hp)) return NULL;
-
        /*
         *      For small heaps (< 40 elements) the
         *      increase in memory locality gives us
         *      a 100% performance increase
         *      (talloc headers are big);
         */
-       h = (fr_heap_ext_t *)talloc_array(hp, uint8_t, sizeof(fr_heap_ext_t) + (sizeof(void *) * (init + 1)));
+       h = (fr_heap_t *)talloc_array(ctx, uint8_t, sizeof(fr_heap_t) + (sizeof(void *) * (init + 1)));
        if (unlikely(!h)) return NULL;
-       talloc_set_type(h, fr_heap_ext_t);
+       talloc_set_type(h, fr_heap_t);
 
-       *h = (fr_heap_ext_t){
+       *h = (fr_heap_t){
                .size = init,
+               .min = init,
                .type = type,
                .cmp = cmp,
                .offset = offset
@@ -88,17 +86,15 @@ fr_heap_t *_fr_heap_alloc(TALLOC_CTX *ctx, fr_heap_cmp_t cmp, char const *type,
         */
        h->p[0] = (void *)UINTPTR_MAX;
 
-       *hp = h;
-
-       return hp;
+       return h;
 }
 
-static inline CC_HINT(always_inline, nonnull) fr_heap_index_t index_get(fr_heap_ext_t *h, void *data)
+static inline CC_HINT(always_inline, nonnull) fr_heap_index_t index_get(fr_heap_t *h, void *data)
 {
        return *((fr_heap_index_t const *)(((uint8_t const *)data) + h->offset));
 }
 
-static inline CC_HINT(always_inline, nonnull) void index_set(fr_heap_ext_t *h, void *data, fr_heap_index_t idx)
+static inline CC_HINT(always_inline, nonnull) void index_set(fr_heap_t *h, void *data, fr_heap_index_t idx)
 {
        *((fr_heap_index_t *)(((uint8_t *)data) + h->offset)) = idx;
 }
@@ -106,6 +102,26 @@ static inline CC_HINT(always_inline, nonnull) void index_set(fr_heap_ext_t *h, v
 #define OFFSET_SET(_heap, _idx) index_set(_heap, _heap->p[_idx], _idx);
 #define OFFSET_RESET(_heap, _idx) index_set(_heap, _heap->p[_idx], 0);
 
+static inline CC_HINT(always_inline)
+int realloc_heap(fr_heap_t **hp, unsigned int n_size)
+{
+       fr_heap_t *h = *hp;
+
+       h = (fr_heap_t *)talloc_realloc(hp, h, uint8_t, sizeof(fr_heap_t) + (sizeof(void *) * (n_size + 1)));
+       if (unlikely(!h)) {
+               fr_strerror_printf("Failed expanding heap to %u elements (%u bytes)",
+                                  n_size, (n_size * (unsigned int)sizeof(void *)));
+               return -1;
+       }
+       talloc_set_type(h, fr_heap_t);
+       h->size = n_size;
+
+       *hp = h;
+
+       return 0;
+}
+
+
 /** Insert a new element into the heap
  *
  * Insert element in heap. Normally, p != NULL, we insert p in a
@@ -119,15 +135,17 @@ static inline CC_HINT(always_inline, nonnull) void index_set(fr_heap_ext_t *h, v
  * heap is also stored in the element itself at the given offset
  * in bytes.
  *
- * @param[in] hp       The heap to insert an element into.
+ * @param[in,out] hp   The heap to extract an element from.
+ *                     A new pointer value will be written to hp
+ *                     if the heap is resized.
  * @param[in] data     Data to insert into the heap.
  * @return
  *     - 0 on success.
  *     - -1 on failure (heap full or malloc error).
  */
-int fr_heap_insert(fr_heap_t *hp, void *data)
+int fr_heap_insert(fr_heap_t **hp, void *data)
 {
-       fr_heap_ext_t *h = *hp;
+       fr_heap_t *h = *hp;
        fr_heap_index_t child;
 
        child = index_get(h, data);
@@ -165,14 +183,8 @@ int fr_heap_insert(fr_heap_t *hp, void *data)
                        n_size = h->size * 2;
                }
 
-               h = (fr_heap_ext_t *)talloc_realloc(hp, h, uint8_t, sizeof(fr_heap_ext_t) + (sizeof(void *) * (n_size + 1)));
-               if (unlikely(!h)) {
-                       fr_strerror_printf("Failed expanding heap to %u elements (%u bytes)",
-                                          n_size, (n_size * (unsigned int)sizeof(void *)));
-                       return -1;
-               }
-               talloc_set_type(h, fr_heap_ext_t);
-               h->size = n_size;
+               if (realloc_heap(&h, n_size) < 0) return -1;
+
                *hp = h;
        }
 
@@ -184,7 +196,7 @@ int fr_heap_insert(fr_heap_t *hp, void *data)
        return 0;
 }
 
-static inline CC_HINT(always_inline) void fr_heap_bubble(fr_heap_ext_t *h, fr_heap_index_t child)
+static inline CC_HINT(always_inline) void fr_heap_bubble(fr_heap_t *h, fr_heap_index_t child)
 {
        if (!fr_cond_assert(child > 0)) return;
 
@@ -211,15 +223,17 @@ static inline CC_HINT(always_inline) void fr_heap_bubble(fr_heap_ext_t *h, fr_he
 
 /** Remove a node from the heap
  *
- * @param[in] hp       The heap to extract an element from.
+ * @param[in,out] hp   The heap to extract an element from.
+ *                     A new pointer value will be written to hp
+ *                     if the heap is resized.
  * @param[in] data     Data to extract from the heap.
  * @return
  *     - 0 on success.
  *     - -1 on failure (no elements or data not found).
  */
-int fr_heap_extract(fr_heap_t *hp, void *data)
+int fr_heap_extract(fr_heap_t **hp, void *data)
 {
-       fr_heap_ext_t *h = *hp;
+       fr_heap_t *h = *hp;
        fr_heap_index_t parent, child, max;
 
        /*
@@ -259,6 +273,16 @@ int fr_heap_extract(fr_heap_t *hp, void *data)
        }
        h->num_elements--;
 
+       /*
+        *      If the number of elements in the heap is half
+        *      what we need, shrink the heap back.
+        */
+       if ((h->num_elements * 2) < h->size) {
+               unsigned int n_size = ROUND_UP_DIV(h->size, 2);
+
+               if ((n_size > h->min) && (realloc_heap(&h, n_size)) == 0) *hp = h;
+       }
+
        /*
         *      We didn't end up at the last element in the heap.
         *      This element has to be re-inserted.
@@ -276,9 +300,18 @@ int fr_heap_extract(fr_heap_t *hp, void *data)
        return 0;
 }
 
-void *fr_heap_pop(fr_heap_t *hp)
+/** Remove a node from the heap
+ *
+ * @param[in,out] hp   The heap to pop an element from.
+ *                     A new pointer value will be written to hp
+ *                     if the heap is resized.
+ * @return
+ *      - The item that was popped.
+ *     - NULL on error.
+ */
+void *fr_heap_pop(fr_heap_t **hp)
 {
-       fr_heap_ext_t *h = *hp;
+       fr_heap_t *h = *hp;
 
        void *data;
 
@@ -294,17 +327,15 @@ void *fr_heap_pop(fr_heap_t *hp)
  *
  * @note If the heap is modified the iterator should be considered invalidated.
  *
- * @param[in] hp       to iterate over.
+ * @param[in] h                to iterate over.
  * @param[in] iter     Pointer to an iterator struct, used to maintain
  *                     state between calls.
  * @return
  *     - User data.
  *     - NULL if at the end of the list.
  */
-void *fr_heap_iter_init(fr_heap_t *hp, fr_heap_iter_t *iter)
+void *fr_heap_iter_init(fr_heap_t *h, fr_heap_iter_t *iter)
 {
-       fr_heap_ext_t *h = *hp;
-
        *iter = 1;
 
        if (h->num_elements == 0) return NULL;
@@ -316,17 +347,15 @@ void *fr_heap_iter_init(fr_heap_t *hp, fr_heap_iter_t *iter)
  *
  * @note If the heap is modified the iterator should be considered invalidated.
  *
- * @param[in] hp       to iterate over.
+ * @param[in] h                to iterate over.
  * @param[in] iter     Pointer to an iterator struct, used to maintain
  *                     state between calls.
  * @return
  *     - User data.
  *     - NULL if at the end of the list.
  */
-void *fr_heap_iter_next(fr_heap_t *hp, fr_heap_iter_t *iter)
+void *fr_heap_iter_next(fr_heap_t *h, fr_heap_iter_t *iter)
 {
-       fr_heap_ext_t *h = *hp;
-
        if ((*iter + 1) > h->num_elements) return NULL;
        *iter += 1;
 
@@ -334,12 +363,10 @@ void *fr_heap_iter_next(fr_heap_t *hp, fr_heap_iter_t *iter)
 }
 
 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
-void fr_heap_verify(char const *file, int line, fr_heap_t *hp)
+void fr_heap_verify(char const *file, int line, fr_heap_t *h)
 {
-       fr_heap_ext_t   *h;
-
-       fr_fatal_assert_msg(hp, "CONSISTENCY CHECK FAILED %s[%i]: fr_heap_t pointer was NULL", file, line);
-       (void) talloc_get_type_abort(hp, fr_heap_t);
+       fr_fatal_assert_msg(h, "CONSISTENCY CHECK FAILED %s[%i]: fr_heap_t pointer was NULL", file, line);
+       (void) talloc_get_type_abort(h, fr_heap_t);
 
        /*
         *      Allocating the heap structure and the array holding the heap as described in data structure
@@ -347,9 +374,8 @@ void fr_heap_verify(char const *file, int line, fr_heap_t *hp)
         *      fr_heap_t * isn't realloc()ed out from under the user, hence the following (and the use of h
         *      rather than hp to access anything in the heap structure).
         */
-       h = *hp;
        fr_fatal_assert_msg(h, "CONSISTENCY CHECK FAILED %s[%i]: heap_t pointer was NULL", file, line);
-       (void) talloc_get_type_abort(h, fr_heap_ext_t);
+       (void) talloc_get_type_abort(h, fr_heap_t);
 
        fr_fatal_assert_msg(h->num_elements <= h->size,
                            "CONSISTENCY CHECK FAILED %s[%i]: num_elements exceeds size", file, line);
index 1ff4781220070ccadf51cff28d8a6af7b250d698..ea90c9bfa8be6b080460563ae031c6745e3a1678 100644 (file)
@@ -62,14 +62,11 @@ typedef int8_t (*fr_heap_cmp_t)(void const *a, void const *b);
  * of the minimum element.  The heap entry can contain an "int"
  * field that holds the entries position in the heap.  The offset
  * of the field is held inside of the heap structure.
- *
- * The reason why we have fr_heap_ext_t and fr_heap_t, is that
- * fr_heap_t is a pointer to a fr_heap_ext_t.  This means that
- * the heap cann be a single contiguous memory chunk, and can
- * be reallocated during extension.
  */
 typedef struct {
        unsigned int    _CONST size;            //!< Number of nodes allocated.
+       unsigned int    _CONST min;             //!< Minimum number of elements we allow
+                                               ///< the heap to reduce down to.
        size_t          _CONST offset;          //!< Offset of heap index in element structure.
 
        unsigned int    _CONST num_elements;    //!< Number of nodes used.
@@ -78,15 +75,11 @@ typedef struct {
        fr_heap_cmp_t   _CONST cmp;             //!< Comparator function.
 
        void            * _CONST p[];           //!< Array of nodes.
-} fr_heap_ext_t;
+} fr_heap_t;
 
 typedef unsigned int fr_heap_index_t;
 typedef unsigned int fr_heap_iter_t;
 
-/** How many talloc headers need to be pre-allocated for a heap
- */
-typedef fr_heap_ext_t * fr_heap_t;
-
 /** How many talloc headers need to be pre-allocated for a heap
  */
 #define FR_HEAP_TALLOC_HEADERS 2
@@ -133,15 +126,13 @@ static inline bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
 
 /** Return the item from the top of the heap but don't pop it
  *
- * @param[in] hp       to return element from.
+ * @param[in] h                to return element from.
  * @return
  *     - Element at the top of the heap.
  *     - NULL if no elements remain in the heap.
  */
-static inline void *fr_heap_peek(fr_heap_t *hp)
+static inline void *fr_heap_peek(fr_heap_t *h)
 {
-       fr_heap_ext_t *h = *hp;
-
        if (h->num_elements == 0) return NULL;
 
        return h->p[1];
@@ -149,16 +140,14 @@ static inline void *fr_heap_peek(fr_heap_t *hp)
 
 /** Peek at a specific index in the heap
  *
- * @param[in] hp       to return element from.
+ * @param[in] h                to return element from.
  * @param[in] idx      to lookup
  * @return
  *     - Element at the top of the heap.
  *     - NULL if index outside of the range of the heap.
  */
-static inline void *fr_heap_peek_at(fr_heap_t *hp, fr_heap_index_t idx)
+static inline void *fr_heap_peek_at(fr_heap_t *h, fr_heap_index_t idx)
 {
-       fr_heap_ext_t *h = *hp;
-
        if (unlikely(idx > h->num_elements)) return NULL;
 
        return h->p[idx];
@@ -166,15 +155,13 @@ static inline void *fr_heap_peek_at(fr_heap_t *hp, fr_heap_index_t idx)
 
 /** Peek at the last element in the heap (not necessarily the bottom)
  *
- * @param[in] hp       to return element from.
+ * @param[in] h                to return element from.
  * @return
  *     - Last element in the heap.
  *     - NULL if no elements remain in the heap.
  */
-static inline void *fr_heap_peek_tail(fr_heap_t *hp)
+static inline void *fr_heap_peek_tail(fr_heap_t *h)
 {
-       fr_heap_ext_t *h = *hp;
-
        if (h->num_elements == 0) return NULL;
 
        /*
@@ -185,18 +172,16 @@ static inline void *fr_heap_peek_tail(fr_heap_t *hp)
 
 /** Return the number of elements in the heap
  *
- * @param[in] hp       to return the number of elements from.
+ * @param[in] h                to return the number of elements from.
  */
-static inline unsigned int fr_heap_num_elements(fr_heap_t *hp)
+static inline unsigned int fr_heap_num_elements(fr_heap_t *h)
 {
-       fr_heap_ext_t *h = *hp;
-
        return h->num_elements;
 }
 
-int            fr_heap_insert(fr_heap_t *hp, void *data) CC_HINT(nonnull);
-int            fr_heap_extract(fr_heap_t *hp, void *data) CC_HINT(nonnull);
-void           *fr_heap_pop(fr_heap_t *hp) CC_HINT(nonnull);
+int            fr_heap_insert(fr_heap_t **hp, void *data) CC_HINT(nonnull);
+int            fr_heap_extract(fr_heap_t **hp, void *data) CC_HINT(nonnull);
+void           *fr_heap_pop(fr_heap_t **hp) CC_HINT(nonnull);
 
 void           *fr_heap_iter_init(fr_heap_t *hp, fr_heap_iter_t *iter) CC_HINT(nonnull);
 void           *fr_heap_iter_next(fr_heap_t *hp, fr_heap_iter_t *iter) CC_HINT(nonnull);
index e1ef1246ac5ffa48f85087d79cc5097765b51625..300effad76ab911c2990b286cf5ba46b34543f3b 100644 (file)
@@ -3,10 +3,9 @@
 
 #include "heap.c"
 
-static bool fr_heap_check(fr_heap_t *hp, void *data)
+static bool fr_heap_check(fr_heap_t *h, void *data)
 {
        unsigned int i;
-       fr_heap_ext_t *h = *hp;
 
        if (!h || (h->num_elements == 0)) return false;
 
@@ -74,7 +73,7 @@ static void heap_test(int skip)
        TEST_CASE("insertions");
        for (i = 0; i < HEAP_TEST_SIZE; i++) {
                FR_HEAP_VERIFY(hp);
-               TEST_CHECK((ret = fr_heap_insert(hp, &array[i])) >= 0);
+               TEST_CHECK((ret = fr_heap_insert(&hp, &array[i])) >= 0);
                TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
 
                TEST_CHECK(fr_heap_check(hp, &array[i]));
@@ -92,7 +91,7 @@ static void heap_test(int skip)
                        TEST_CHECK(array[entry].heap != 0);
                        TEST_MSG("element %i removed out of order", entry);
 
-                       TEST_CHECK((ret = fr_heap_extract(hp, &array[entry])) >= 0);
+                       TEST_CHECK((ret = fr_heap_extract(&hp, &array[entry])) >= 0);
                        TEST_MSG("element %i removal failed, returned %i - %s", entry, ret, fr_strerror());
 
                        TEST_CHECK(!fr_heap_check(hp, &array[entry]));
@@ -111,7 +110,7 @@ static void heap_test(int skip)
                TEST_CHECK((t = fr_heap_peek(hp)) != NULL);
                TEST_MSG("expected %i elements remaining in the heap", left - i);
 
-               TEST_CHECK(fr_heap_extract(hp, t) >= 0);
+               TEST_CHECK(fr_heap_extract(&hp, t) >= 0);
                TEST_MSG("failed extracting %i", i);
        }
 
@@ -168,7 +167,7 @@ static void heap_test_order(void)
 
        TEST_CASE("insertions");
        for (i = 0; i < HEAP_TEST_SIZE; i++) {
-               TEST_CHECK((ret = fr_heap_insert(hp, &array[i])) >= 0);
+               TEST_CHECK((ret = fr_heap_insert(&hp, &array[i])) >= 0);
                TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
 
                TEST_CHECK(fr_heap_check(hp, &array[i]));
@@ -177,7 +176,7 @@ static void heap_test_order(void)
 
        TEST_CASE("ordering");
 
-       while ((thing = fr_heap_pop(hp))) {
+       while ((thing = fr_heap_pop(&hp))) {
                TEST_CHECK(thing->data >= data);
                TEST_MSG("Expected data >= %i, got %i", data, thing->data);
                if (thing->data >= data) data = thing->data;
@@ -207,7 +206,7 @@ static void heap_iter(void)
 
        for (size_t i = 0; i < HEAP_ITER_SIZE; i++) {
                array[i].data = i;
-               TEST_CHECK(fr_heap_insert(hp, &array[i])  >= 0);
+               TEST_CHECK(fr_heap_insert(&hp, &array[i])  >= 0);
        }
 
        data_set = 0;
@@ -251,7 +250,7 @@ static void heap_cycle(void)
        start_insert = fr_time();
        TEST_CASE("insertions");
        for (i = 0; i < HEAP_CYCLE_SIZE; i++) {
-               TEST_CHECK((ret = fr_heap_insert(hp, &array[i])) >= 0);
+               TEST_CHECK((ret = fr_heap_insert(&hp, &array[i])) >= 0);
                TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
        }
        TEST_CHECK(fr_heap_num_elements(hp) == HEAP_CYCLE_SIZE);
@@ -269,7 +268,7 @@ static void heap_cycle(void)
                TEST_CHECK((t = fr_heap_peek(hp)) != NULL);
                TEST_MSG("expected %i elements remaining in the heap", to_remove - i);
 
-               TEST_CHECK(fr_heap_extract(hp, t) >= 0);
+               TEST_CHECK(fr_heap_extract(&hp, t) >= 0);
                TEST_MSG("failed extracting %i - %s", i, fr_strerror());
        }
 
@@ -282,11 +281,11 @@ static void heap_cycle(void)
 
        for (i = 0; i < HEAP_CYCLE_SIZE; i++) {
                if (!fr_heap_entry_inserted(array[i].heap)) {
-                       TEST_CHECK((ret = fr_heap_insert(hp, &array[i])) >= 0);
+                       TEST_CHECK((ret = fr_heap_insert(&hp, &array[i])) >= 0);
                        TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
                        inserted++;
                } else {
-                       TEST_CHECK((ret = fr_heap_extract(hp, &array[i])) >= 0);
+                       TEST_CHECK((ret = fr_heap_extract(&hp, &array[i])) >= 0);
                        TEST_MSG("element %i removal failed, returned %i - %s", i, ret, fr_strerror());
                        removed++;
                }
index 849adb9ed0aa498c66fdb04f1f96c8a52e1459bd..e0b7c9955d431e734a002fb1a16481622b928968 100644 (file)
@@ -203,7 +203,7 @@ static void lst_stress_realloc(void)
        for (unsigned int i = 0; i < INITIAL_CAPACITY; i++) {
                TEST_CHECK((ret = fr_lst_insert(lst, &lst_array[i])) >= 0);
                TEST_MSG("lst insert failed, iteration %d; returned %i - %s", i, ret, fr_strerror());
-               TEST_CHECK((ret = fr_heap_insert(hp, &hp_array[i])) >= 0);
+               TEST_CHECK((ret = fr_heap_insert(&hp, &hp_array[i])) >= 0);
                TEST_MSG("heap insert failed, iteration %d; returned %i - %s", i, ret, fr_strerror());
        }
 
@@ -211,7 +211,7 @@ static void lst_stress_realloc(void)
        TEST_CASE("partial pop");
        for (unsigned int i = 0; i < INITIAL_CAPACITY / 2; i++) {
                TEST_CHECK((from_lst = fr_lst_pop(lst)) != NULL);
-               TEST_CHECK((from_hp = fr_heap_pop(hp)) != NULL);
+               TEST_CHECK((from_hp = fr_heap_pop(&hp)) != NULL);
                TEST_CHECK(lst_cmp(from_lst, from_hp) == 0);
        }
 
@@ -224,7 +224,7 @@ static void lst_stress_realloc(void)
        for (unsigned int i = INITIAL_CAPACITY; i < 2 * INITIAL_CAPACITY; i++) {
                TEST_CHECK((ret = fr_lst_insert(lst, &lst_array[i])) >= 0);
                TEST_MSG("lst insert failed, iteration %u; returned %i - %s", i, ret, fr_strerror());
-               TEST_CHECK((ret = fr_heap_insert(hp, &hp_array[i])) >= 0);
+               TEST_CHECK((ret = fr_heap_insert(&hp, &hp_array[i])) >= 0);
                TEST_MSG("heap insert failed, iteration %u; returned %i - %s", i, ret, fr_strerror());
        }
 
@@ -232,7 +232,7 @@ static void lst_stress_realloc(void)
        TEST_CASE("complete pop");
        for (unsigned int i = 0; i < 3 * INITIAL_CAPACITY / 2; i++) {
                TEST_CHECK((from_lst = fr_lst_pop(lst)) != NULL);
-               TEST_CHECK((from_hp = fr_heap_pop(hp)) != NULL);
+               TEST_CHECK((from_hp = fr_heap_pop(&hp)) != NULL);
                TEST_CHECK(lst_cmp(from_lst, from_hp) == 0);
        }
 
@@ -444,7 +444,7 @@ static CC_HINT(noinline) lst_thing *array_pop(lst_thing **array, unsigned int co
 static void queue_cmp(unsigned int count)
 {
        fr_lst_t        *lst;
-       fr_heap_t       *heap;
+       fr_heap_t       *hp;
 
        lst_thing       *values;
 
@@ -497,17 +497,17 @@ static void queue_cmp(unsigned int count)
                populate_values(values, count);
 
                start_alloc = fr_time();
-               heap = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, count);
+               hp = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, count);
                end_alloc = fr_time();
-               TEST_CHECK(heap != NULL);
+               TEST_CHECK(hp != NULL);
 
                start_insert = fr_time();
-               for (i = 0; i < count; i++) fr_heap_insert(heap, &values[i]);
+               for (i = 0; i < count; i++) fr_heap_insert(&hp, &values[i]);
                end_insert = fr_time();
 
                start_pop = fr_time();
                for (i = 0; i < count; i++) {
-                       TEST_CHECK(fr_heap_pop(heap) != NULL);
+                       TEST_CHECK(fr_heap_pop(&hp) != NULL);
                        if (i == 0) end_pop_first = fr_time();
 
                        TEST_MSG("expected %u elements remaining in the heap", count - i);
@@ -521,7 +521,7 @@ static void queue_cmp(unsigned int count)
                TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
                TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
 
-               talloc_free(heap);
+               talloc_free(hp);
        }
 
        /*
index 1d641b576d2dc0306592ba3d6f66ede26ecfdf4b..61464928e33a9f25177bd6e2f27d7345734c1a01 100644 (file)
@@ -388,7 +388,7 @@ static CC_HINT(noinline) minmax_heap_thing *array_pop(minmax_heap_thing **array,
 static void queue_cmp(unsigned int count)
 {
        fr_minmax_heap_t        *minmax;
-       fr_heap_t               *heap;
+       fr_heap_t               *hp;
 
        minmax_heap_thing       *values;
 
@@ -440,17 +440,17 @@ static void queue_cmp(unsigned int count)
                populate_values(values, count);
 
                start_alloc = fr_time();
-               heap = fr_heap_alloc(NULL, minmax_heap_cmp, minmax_heap_thing, idx, count);
+               hp = fr_heap_alloc(NULL, minmax_heap_cmp, minmax_heap_thing, idx, count);
                end_alloc = fr_time();
-               TEST_CHECK(heap != NULL);
+               TEST_CHECK(hp != NULL);
 
                start_insert = fr_time();
-               for (i = 0; i < count; i++) fr_heap_insert(heap, &values[i]);
+               for (i = 0; i < count; i++) fr_heap_insert(&hp, &values[i]);
                end_insert = fr_time();
 
                start_pop = fr_time();
                for (i = 0; i < count; i++) {
-                       TEST_CHECK(fr_heap_pop(heap) != NULL);
+                       TEST_CHECK(fr_heap_pop(&hp) != NULL);
                        if (i == 0) end_pop_first = fr_time();
 
                        TEST_MSG("expected %u elements remaining in the heap", count - i);
@@ -464,7 +464,7 @@ static void queue_cmp(unsigned int count)
                TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
                TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
 
-               talloc_free(heap);
+               talloc_free(hp);
        }
 
        /*
index 3b7db33528942c1b7167eb3a438022207267a37b..291e2b05e0ff94ad4ff9bd052f9d8de9b7c26802 100644 (file)
@@ -467,7 +467,7 @@ static void request_queued(request_t *request, fr_state_signal_t action)
                break;
 
        case FR_SIGNAL_CANCEL:
-//             (void) fr_heap_extract(request->backlog, request);
+//             (void) fr_heap_extract(&request->backlog, request);
                //request_delete(request);
                break;
 
index c464d6f8c7496699cb20023549e59cb93788901d..e0ed9d692817698516c88856a7f36d3be33cd2b1 100644 (file)
@@ -166,7 +166,7 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out,
         */
        c = fr_heap_peek(driver->heap);
        if (c && (fr_unix_time_lt(c->expires, fr_time_to_unix_time(request->packet->timestamp)))) {
-               fr_heap_extract(driver->heap, c);
+               fr_heap_extract(&driver->heap, c);
                fr_rb_delete(driver->cache, c);
                talloc_free(c);
        }
@@ -202,7 +202,7 @@ static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config
        c = fr_rb_find(driver->cache, &(rlm_cache_entry_t){ .key = key, .key_len = key_len });
        if (!c) return CACHE_MISS;
 
-       fr_heap_extract(driver->heap, c);
+       fr_heap_extract(&driver->heap, c);
        fr_rb_delete(driver->cache, c);
        talloc_free(c);
 
@@ -241,7 +241,7 @@ static cache_status_t cache_entry_insert(rlm_cache_config_t const *config, void
                }
        }
 
-       if (fr_heap_insert(driver->heap, UNCONST(rlm_cache_entry_t *, c)) < 0) {
+       if (fr_heap_insert(&driver->heap, UNCONST(rlm_cache_entry_t *, c)) < 0) {
                fr_rb_delete(driver->cache, c);
                RERROR("Failed adding entry to expiry heap");
 
@@ -267,12 +267,12 @@ static cache_status_t cache_entry_set_ttl(UNUSED rlm_cache_config_t const *confi
        if (!request) return CACHE_ERROR;
 #endif
 
-       if (!fr_cond_assert(fr_heap_extract(driver->heap, c) == 0)) {
+       if (!fr_cond_assert(fr_heap_extract(&driver->heap, c) == 0)) {
                RERROR("Entry not in heap");
                return CACHE_ERROR;
        }
 
-       if (fr_heap_insert(driver->heap, c) < 0) {
+       if (fr_heap_insert(&driver->heap, c) < 0) {
                fr_rb_delete(driver->cache, c); /* make sure we don't leak entries... */
                RERROR("Failed updating entry TTL.  Entry was forcefully expired");
                return CACHE_ERROR;