From 1a95bc42c7d4b2b48edc3323b353292f181cf7cb Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 23 Aug 2025 19:57:29 +0200 Subject: [PATCH] MEDIUM: proxy: index proxy ID using compact trees The proxy 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 proxy for this node, plus 8 bytes in the root (which is static so not much relevant here). Now the proxy is 3088 bytes large. --- include/haproxy/proxy-t.h | 4 ++-- include/haproxy/proxy.h | 6 +++--- src/cfgparse-listen.c | 1 - src/cfgparse.c | 2 +- src/cli.c | 2 +- src/proxy.c | 18 +++++++----------- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index 6d93eeb54..66b9f110a 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -441,7 +441,7 @@ struct proxy { char *check_path; /* PATH environment to use for external agent checks */ struct http_reply *replies[HTTP_ERR_SIZE]; /* HTTP replies for known errors */ unsigned int log_count; /* number of logs produced by the frontend */ - int uuid; /* universally unique proxy ID, used for SNMP */ + int uuid; /* universally unique proxy ID, used for SNMP, indexed by conf.uuid_node below */ unsigned int backlog; /* force the frontend's listen backlog */ unsigned int li_all; /* total number of listeners attached to this proxy */ unsigned int li_paused; /* total number of listeners paused (LI_PAUSED) */ @@ -460,7 +460,7 @@ struct proxy { struct { const char *file; /* file where the section appears */ - struct eb32_node id; /* place in the tree of used IDs */ + 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 eb_root used_server_id; /* list of server IDs in use */ diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h index 98df4d1e6..c1407c3cc 100644 --- a/include/haproxy/proxy.h +++ b/include/haproxy/proxy.h @@ -22,7 +22,7 @@ #ifndef _HAPROXY_PROXY_H #define _HAPROXY_PROXY_H -#include +#include #include #include @@ -36,7 +36,7 @@ extern struct proxy *proxies_list; extern struct list proxies; -extern struct eb_root used_proxy_id; /* list of proxy IDs in use */ +extern struct ceb_root *used_proxy_id; /* list of proxy IDs in use */ extern unsigned int error_snapshot_id; /* global ID assigned to each error then incremented */ extern struct ceb_root *proxy_by_name; /* tree of proxies sorted by name */ @@ -125,7 +125,7 @@ static inline struct proxy *proxy_be_by_name(const char *name) /* index proxy 's id into used_proxy_id */ static inline void proxy_index_id(struct proxy *px) { - eb32_insert(&used_proxy_id, &px->conf.id); + ceb32_item_insert(&used_proxy_id, conf.uuid_node, uuid, px); } /* this function initializes all timeouts for proxy p */ diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 4cfd86307..b47e587f4 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -732,7 +732,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } curproxy->uuid = atol(args[1]); - curproxy->conf.id.key = curproxy->uuid; curproxy->options |= PR_O_FORCED_ID; if (curproxy->uuid <= 0) { diff --git a/src/cfgparse.c b/src/cfgparse.c index 26239b484..7814ceadc 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2851,7 +2851,7 @@ init_proxies_list_stage1: * possibly reuse existing IDs. */ next_pxid = proxy_get_next_id(next_pxid); - curproxy->conf.id.key = curproxy->uuid = next_pxid; + curproxy->uuid = next_pxid; proxy_index_id(curproxy); } diff --git a/src/cli.c b/src/cli.c index 60f0119c5..331764531 100644 --- a/src/cli.c +++ b/src/cli.c @@ -466,7 +466,7 @@ static struct proxy *cli_alloc_fe(const char *name, const char *file, int line) fe->default_target = &cli_applet.obj_type; /* the stats frontend is the only one able to assign ID #0 */ - fe->conf.id.key = fe->uuid = 0; + fe->uuid = 0; proxy_index_id(fe); return fe; } diff --git a/src/proxy.c b/src/proxy.c index a9ca53482..733994564 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -61,7 +61,7 @@ int listeners; /* # of proxy listeners, set by cfgparse */ struct proxy *proxies_list = NULL; /* list of main proxies */ struct list proxies = LIST_HEAD_INIT(proxies); /* list of all proxies */ -struct eb_root used_proxy_id = EB_ROOT; /* list of proxy IDs in use */ +struct ceb_root *used_proxy_id = NULL; /* list of proxy IDs in use */ struct ceb_root *proxy_by_name = NULL; /* tree of proxies sorted by name */ struct ceb_root *defproxy_by_name = NULL; /* tree of default proxies sorted by name (dups possible) */ struct proxy *orphaned_default_proxies = NULL; /* deleted ones with refcount != 0 */ @@ -544,11 +544,11 @@ const char *proxy_find_best_option(const char *word, const char **extra) */ uint proxy_get_next_id(uint from) { - struct eb32_node *used; + const struct proxy *px; do { - used = eb32_lookup_ge(&used_proxy_id, from); - if (!used || used->key > from) + px = ceb32_item_lookup_ge(&used_proxy_id, conf.uuid_node, uuid, from, struct proxy); + if (!px || px->uuid > from) return from; /* available */ from++; } while (from); @@ -1200,14 +1200,10 @@ void proxy_store_name(struct proxy *px) */ struct proxy *proxy_find_by_id(int id, int cap, int table) { - struct eb32_node *n; - - for (n = eb32_lookup(&used_proxy_id, id); n; n = eb32_next(n)) { - struct proxy *px = container_of(n, struct proxy, conf.id); - - if (px->uuid != id) - break; + struct proxy *px; + for (px = ceb32_item_lookup(&used_proxy_id, conf.uuid_node, uuid, id, struct proxy); + px ; px = ceb32_item_next_dup(&used_proxy_id, conf.uuid_node, uuid, px)) { if ((px->cap & cap) != cap) continue;