From 66191584d132640ce704d1794bc37c4b57a3168d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 24 Aug 2025 11:12:49 +0200 Subject: [PATCH] MEDIUM: listener: index listener ID using compact trees The listener ID is currently stored as a 32-bit int using an eb32 tree. It's used essentially to find holes in order to automatically assign IDs, and to detect duplicates. Let's change this to use compact trees instead in order to save 24 bytes in struct listener for this node, plus 8 bytes in struct proxy. The struct listener is now 704 bytes large, and the struct proxy 3080. --- include/haproxy/listener-t.h | 7 ++----- include/haproxy/listener.h | 4 ++-- include/haproxy/proxy-t.h | 2 +- src/cfgparse.c | 2 +- src/listener.c | 21 +++++++++------------ src/proxy.c | 2 +- 6 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h index ce7e85019..c36108713 100644 --- a/include/haproxy/listener-t.h +++ b/include/haproxy/listener-t.h @@ -238,7 +238,7 @@ struct listener { enum obj_type obj_type; /* object type = OBJ_TYPE_LISTENER */ enum li_state state; /* state: NEW, INIT, ASSIGNED, LISTEN, READY, FULL */ uint16_t flags; /* listener flags: LI_F_* */ - int luid; /* listener universally unique ID, used for SNMP */ + int luid; /* listener universally unique ID, used for SNMP, indexed by below */ int nbconn; /* current number of connections on this listener */ unsigned long thr_idx; /* thread indexes for queue distribution (see listener_accept()) */ __decl_thread(HA_RWLOCK_T lock); @@ -253,10 +253,7 @@ struct listener { struct list by_bind; /* chaining in bind_conf's list of listeners */ struct bind_conf *bind_conf; /* "bind" line settings, include SSL settings among other things */ struct receiver rx; /* network receiver parts */ - struct { - struct eb32_node id; /* place in the tree of used IDs */ - } conf; /* config information */ - + struct ceb_node luid_node; /* place in the tree of used IDs, indexes above */ struct guid_node guid; /* GUID global tree node */ struct li_per_thread *per_thr; /* per-thread fields (one per thread in the group) */ diff --git a/include/haproxy/listener.h b/include/haproxy/listener.h index 88146e0a4..d8aea274b 100644 --- a/include/haproxy/listener.h +++ b/include/haproxy/listener.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -242,7 +242,7 @@ extern ullong maxconn_reached; /* index listener
  • 's id into proxy 's used_listener_id */ static inline void listener_index_id(struct proxy *px, struct listener *li) { - eb32_insert(&px->conf.used_listener_id, &li->conf.id); + ceb32_item_insert(&px->conf.used_listener_id, luid_node, luid, li); } static inline uint accept_queue_ring_len(const struct accept_queue_ring *ring) diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index 66b9f110a..50da4dcad 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -462,7 +462,7 @@ struct proxy { const char *file; /* file where the section appears */ struct ceb_node uuid_node; /* place in the tree of used IDs, indexes above */ int line; /* line where the section appears */ - struct eb_root used_listener_id;/* list of listener IDs in use */ + struct ceb_root *used_listener_id; /* list of listener IDs in use */ struct eb_root used_server_id; /* list of server IDs in use */ struct ceb_root *used_server_name; /* list of server names in use */ struct list bind; /* list of bind settings */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 7814ceadc..8bc57eebf 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -4291,7 +4291,7 @@ init_proxies_list_stage2: next_id = prev_li->luid + 1; } next_id = listener_get_next_id(curproxy, next_id); - listener->conf.id.key = listener->luid = next_id; + listener->luid = next_id; listener_index_id(curproxy, listener); } next_id++; diff --git a/src/listener.c b/src/listener.c index 87ac573ed..089137b66 100644 --- a/src/listener.c +++ b/src/listener.c @@ -405,11 +405,11 @@ void stop_listener(struct listener *l, int lpx, int lpr, int lli) */ uint listener_get_next_id(const struct proxy *px, uint from) { - const struct eb32_node *used; + const struct listener *li; do { - used = eb32_lookup_ge((struct eb_root*)&px->conf.used_listener_id, from); - if (!used || used->key > from) + li = ceb32_item_lookup_ge(&px->conf.used_listener_id, luid_node, luid, from, struct listener); + if (!li || li->luid > from) return from; /* available */ from++; } while (from); @@ -1870,9 +1870,9 @@ int bind_complete_thread_setup(struct bind_conf *bind_conf, int *err_code) return cfgerr; } /* assign the ID to the first one only */ - new_li->luid = new_li->conf.id.key = tmp_li->luid; + ceb32_item_delete(&fe->conf.used_listener_id, luid_node, luid, tmp_li); + new_li->luid = tmp_li->luid; tmp_li->luid = 0; - eb32_delete(&tmp_li->conf.id); if (new_li->luid) listener_index_id(fe, new_li); new_li = tmp_li; @@ -1894,9 +1894,9 @@ int bind_complete_thread_setup(struct bind_conf *bind_conf, int *err_code) return cfgerr; } /* assign the ID to the first one only */ - new_li->luid = new_li->conf.id.key = li->luid; + ceb32_item_delete(&fe->conf.used_listener_id, luid_node, luid, li); + new_li->luid = li->luid; li->luid = 0; - eb32_delete(&li->conf.id); if (new_li->luid) listener_index_id(fe, new_li); } @@ -2220,7 +2220,6 @@ static int bind_parse_guid_prefix(char **args, int cur_arg, struct proxy *px, st /* parse the "id" bind keyword */ static int bind_parse_id(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { - struct eb32_node *node; struct listener *l, *new; char *error; @@ -2240,16 +2239,14 @@ static int bind_parse_id(char **args, int cur_arg, struct proxy *px, struct bind memprintf(err, "'%s' : expects an integer argument, found '%s'", args[cur_arg], args[cur_arg + 1]); return ERR_ALERT | ERR_FATAL; } - new->conf.id.key = new->luid; if (new->luid <= 0) { memprintf(err, "'%s' : custom id has to be > 0", args[cur_arg]); return ERR_ALERT | ERR_FATAL; } - node = eb32_lookup(&px->conf.used_listener_id, new->luid); - if (node) { - l = container_of(node, struct listener, conf.id); + l = ceb32_item_lookup(&px->conf.used_listener_id, luid_node, luid, new->luid, struct listener); + if (l) { memprintf(err, "'%s' : custom id %d already used at %s:%d ('bind %s')", args[cur_arg], l->luid, l->bind_conf->file, l->bind_conf->line, l->bind_conf->arg); diff --git a/src/proxy.c b/src/proxy.c index 733994564..524c886d4 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -1476,7 +1476,7 @@ void init_new_proxy(struct proxy *p) MT_LIST_INIT(&p->lbprm.lb_free_list); - p->conf.used_listener_id = EB_ROOT; + p->conf.used_listener_id = NULL; p->conf.used_server_id = EB_ROOT; p->used_server_addr = NULL;