]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: proxy: switch conf.name to cebis_tree
authorWilly Tarreau <w@1wt.eu>
Tue, 15 Jul 2025 09:47:54 +0000 (11:47 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 16 Sep 2025 07:23:46 +0000 (09:23 +0200)
This is used to index the proxy's name and it contains a copy of the
pointer to the proxy's name in <id>. Changing that for a ceb_node placed
just before <id> saves 32 bytes to the struct proxy, which is now 3112
bytes large.

Here we need to continue to support duplicates since they're still
allowed between type-incompatible proxies.

Interestingly, the use of cebis_next_dup() instead of cebis_next() in
proxy_find_by_name() allows us to get rid of an strcmp() that was
performed for each use_backend rule. A test with a large config
(100k backends) shows that we can get 3% extra performance on a
config involving a static use_backend rule (3.09M to 3.18M rps),
and even 4.5% on a dynamic rule selecting a random backend (2.47M
to 2.59M).

include/haproxy/proxy-t.h
include/haproxy/proxy.h
src/proxy.c

index 1bf0008cdc2471e215c62dfb65896f9f8d4e5485..6d93eeb54481a4ebd3f61cb5f924d7fe9fd15fb3 100644 (file)
@@ -396,7 +396,8 @@ struct proxy {
        } timeout;
        __decl_thread(HA_RWLOCK_T lock);        /* may be taken under the server's lock */
 
-       char *id, *desc;                        /* proxy id (name) and description */
+       char *id;                               /* proxy id (name), indexed by <conf.name_node> below */
+       char *desc;                             /* proxy description */
        struct proxy_per_tgroup *per_tgrp;      /* array of per-tgroup stuff such as queues */
        unsigned int queueslength;              /* Sum of the length of each queue */
        int totpend;                            /* total number of pending connections on this instance (for stats) */
@@ -468,7 +469,7 @@ struct proxy {
                struct list listeners;          /* list of listeners belonging to this frontend */
                struct list errors;             /* list of all custom error files */
                struct arg_list args;           /* sample arg list that need to be resolved */
-               struct ebpt_node by_name;       /* proxies are stored sorted by name here */
+               struct ceb_node name_node;      /* proxies are stored sorted by name here; indexes <id> below */
                struct list lf_checks;          /* list of logformats found in the proxy section that needs to be checked during postparse */
                struct log_steps log_steps;     /* bitfield of log origins where log should be generated during request handling */
                const char *file_prev;          /* file of the previous instance found with the same name, or NULL */
index 502d7ba6abe920a2589804b881f8040709cb53cc..2329db8b79f51f1d31333113bbb616cbd6458180 100644 (file)
@@ -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 unsigned int error_snapshot_id;  /* global ID assigned to each error then incremented */
-extern struct eb_root proxy_by_name;    /* tree of proxies sorted by name */
+extern struct ceb_root *proxy_by_name;    /* tree of proxies sorted by name */
 
 extern const struct cfg_opt cfg_opts[];
 extern const struct cfg_opt cfg_opts2[];
index 038870e0e5c64d91842cf17f2bbb380ae3da9b71..c886e74732903fe920559605b59328616c3708a4 100644 (file)
@@ -16,8 +16,8 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 
+#include <import/cebis_tree.h>
 #include <import/eb32tree.h>
-#include <import/ebistree.h>
 
 #include <haproxy/acl.h>
 #include <haproxy/api.h>
@@ -62,8 +62,8 @@ 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 eb_root proxy_by_name = EB_ROOT; /* tree of proxies sorted by name */
-struct eb_root defproxy_by_name = EB_ROOT; /* tree of default proxies sorted by name (dups possible) */
+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 */
 unsigned int error_snapshot_id = 0;     /* global ID assigned to each error then incremented */
 
@@ -217,7 +217,7 @@ static inline void proxy_free_common(struct proxy *px)
        struct lf_expr *lf, *lfb;
 
        /* note that the node's key points to p->id */
-       ebpt_delete(&px->conf.by_name);
+       cebis_item_delete((px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name, conf.name_node, id, px);
        ha_free(&px->id);
        LIST_DEL_INIT(&px->global_list);
        drop_file_name(&px->conf.file);
@@ -1172,10 +1172,9 @@ static int proxy_parse_guid(char **args, int section_type, struct proxy *curpx,
  */
 void proxy_store_name(struct proxy *px)
 {
-       struct eb_root *root = (px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name;
+       struct ceb_root **root = (px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name;
 
-       px->conf.by_name.key = px->id;
-       ebis_insert(root, &px->conf.by_name);
+       cebis_item_insert(root, conf.name_node, id, px);
 }
 
 /* Returns a pointer to the first proxy matching capabilities <cap> and id
@@ -1219,16 +1218,11 @@ struct proxy *proxy_find_by_name(const char *name, int cap, int table)
                        return curproxy;
        }
        else {
-               struct eb_root *root;
-               struct ebpt_node *node;
+               struct ceb_root **root;
 
                root = (cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name;
-               for (node = ebis_lookup(root, name); node; node = ebpt_next(node)) {
-                       curproxy = container_of(node, struct proxy, conf.by_name);
-
-                       if (strcmp(curproxy->id, name) != 0)
-                               break;
-
+               for (curproxy = cebis_item_lookup(root, conf.name_node, id, name, struct proxy);
+                    curproxy; curproxy = cebis_item_next_dup(root, conf.name_node, id, curproxy)) {
                        if ((curproxy->cap & cap) != cap)
                                continue;
 
@@ -1583,7 +1577,8 @@ void proxy_destroy_defaults(struct proxy *px)
        if (!(px->cap & PR_CAP_DEF))
                return;
        BUG_ON(px->conf.refcount != 0);
-       ebpt_delete(&px->conf.by_name);
+       cebis_item_delete((px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name,
+                         conf.name_node, id, px);
        proxy_free_defaults(px);
        free(px);
 }
@@ -1593,14 +1588,11 @@ void proxy_destroy_defaults(struct proxy *px)
  */
 void proxy_destroy_all_unref_defaults()
 {
-       struct ebpt_node *n;
        struct proxy *px, *nx;
 
-       n = ebpt_first(&defproxy_by_name);
-       while (n) {
-               px = container_of(n, struct proxy, conf.by_name);
+       for (px = cebis_item_first(&defproxy_by_name, conf.name_node, id, struct proxy); px; px = nx) {
                BUG_ON(!(px->cap & PR_CAP_DEF));
-               n = ebpt_next(n);
+               nx = cebis_item_next(&defproxy_by_name, conf.name_node, id, px);
                if (!px->conf.refcount)
                        proxy_destroy_defaults(px);
        }
@@ -1624,7 +1616,7 @@ void proxy_unref_or_destroy_defaults(struct proxy *px)
        if (!px || !(px->cap & PR_CAP_DEF))
                return;
 
-       ebpt_delete(&px->conf.by_name);
+       cebis_item_delete((px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name, conf.name_node, id, px);
        if (px->conf.refcount) {
                /* still referenced just append it to the orphaned list */
                px->next = orphaned_default_proxies;