MEDIUM: proxy: switch conf.name to cebis_tree

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).
This commit is contained in:
Willy Tarreau 2025-07-15 11:47:54 +02:00
parent fdf6fd5b45
commit d0d60a007d
3 changed files with 18 additions and 25 deletions

View File

@ -396,7 +396,8 @@ struct proxy {
} timeout; } timeout;
__decl_thread(HA_RWLOCK_T lock); /* may be taken under the server's lock */ __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 */ struct proxy_per_tgroup *per_tgrp; /* array of per-tgroup stuff such as queues */
unsigned int queueslength; /* Sum of the length of each queue */ unsigned int queueslength; /* Sum of the length of each queue */
int totpend; /* total number of pending connections on this instance (for stats) */ 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 listeners; /* list of listeners belonging to this frontend */
struct list errors; /* list of all custom error files */ struct list errors; /* list of all custom error files */
struct arg_list args; /* sample arg list that need to be resolved */ 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 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 */ 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 */ const char *file_prev; /* file of the previous instance found with the same name, or NULL */

View File

@ -36,7 +36,7 @@ extern struct proxy *proxies_list;
extern struct list proxies; extern struct list proxies;
extern struct eb_root used_proxy_id; /* list of proxy IDs in use */ 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 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_opts[];
extern const struct cfg_opt cfg_opts2[]; extern const struct cfg_opt cfg_opts2[];

View File

@ -16,8 +16,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <import/cebis_tree.h>
#include <import/eb32tree.h> #include <import/eb32tree.h>
#include <import/ebistree.h>
#include <haproxy/acl.h> #include <haproxy/acl.h>
#include <haproxy/api.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 proxy *proxies_list = NULL; /* list of main proxies */
struct list proxies = LIST_HEAD_INIT(proxies); /* list of all 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 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 ceb_root *proxy_by_name = NULL; /* 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 *defproxy_by_name = NULL; /* tree of default proxies sorted by name (dups possible) */
struct proxy *orphaned_default_proxies = NULL; /* deleted ones with refcount != 0 */ 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 */ 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; struct lf_expr *lf, *lfb;
/* note that the node's key points to p->id */ /* 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); ha_free(&px->id);
LIST_DEL_INIT(&px->global_list); LIST_DEL_INIT(&px->global_list);
drop_file_name(&px->conf.file); 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) 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; cebis_item_insert(root, conf.name_node, id, px);
ebis_insert(root, &px->conf.by_name);
} }
/* Returns a pointer to the first proxy matching capabilities <cap> and id /* 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; return curproxy;
} }
else { else {
struct eb_root *root; struct ceb_root **root;
struct ebpt_node *node;
root = (cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name; root = (cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name;
for (node = ebis_lookup(root, name); node; node = ebpt_next(node)) { for (curproxy = cebis_item_lookup(root, conf.name_node, id, name, struct proxy);
curproxy = container_of(node, struct proxy, conf.by_name); curproxy; curproxy = cebis_item_next_dup(root, conf.name_node, id, curproxy)) {
if (strcmp(curproxy->id, name) != 0)
break;
if ((curproxy->cap & cap) != cap) if ((curproxy->cap & cap) != cap)
continue; continue;
@ -1583,7 +1577,8 @@ void proxy_destroy_defaults(struct proxy *px)
if (!(px->cap & PR_CAP_DEF)) if (!(px->cap & PR_CAP_DEF))
return; return;
BUG_ON(px->conf.refcount != 0); 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); proxy_free_defaults(px);
free(px); free(px);
} }
@ -1593,14 +1588,11 @@ void proxy_destroy_defaults(struct proxy *px)
*/ */
void proxy_destroy_all_unref_defaults() void proxy_destroy_all_unref_defaults()
{ {
struct ebpt_node *n;
struct proxy *px, *nx; struct proxy *px, *nx;
n = ebpt_first(&defproxy_by_name); for (px = cebis_item_first(&defproxy_by_name, conf.name_node, id, struct proxy); px; px = nx) {
while (n) {
px = container_of(n, struct proxy, conf.by_name);
BUG_ON(!(px->cap & PR_CAP_DEF)); 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) if (!px->conf.refcount)
proxy_destroy_defaults(px); proxy_destroy_defaults(px);
} }
@ -1624,7 +1616,7 @@ void proxy_unref_or_destroy_defaults(struct proxy *px)
if (!px || !(px->cap & PR_CAP_DEF)) if (!px || !(px->cap & PR_CAP_DEF))
return; 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) { if (px->conf.refcount) {
/* still referenced just append it to the orphaned list */ /* still referenced just append it to the orphaned list */
px->next = orphaned_default_proxies; px->next = orphaned_default_proxies;