From: Willy Tarreau Date: Mon, 17 Feb 2025 08:39:04 +0000 (+0100) Subject: MEDIUM: guid: switch guid to more compact cebuis_tree X-Git-Tag: v3.3-dev9~110 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=91258fb9d899640184e4f89308092b481c861c0d;p=thirdparty%2Fhaproxy.git MEDIUM: guid: switch guid to more compact cebuis_tree The current guid struct size is 56 bytes. Once reduced using compact trees, it goes down to 32 (almost half). We're not on a critical path and size matters here, so better switch to this. It's worth noting that the name part could also be stored in the guid_node at the end to save 8 extra byte (no pointer needed anymore), however the purpose of this struct is to be embedded into other ones, which is not compatible with having a dynamic size. Affected struct sizes in bytes: Before After Diff server 4032 4032 0* proxy 3184 3160 -24 listener 752 728 -24 *: struct server is full of holes and padding (176 bytes) and is 64-byte aligned. Moving the guid_node elsewhere such as after sess_conn reduces it to 3968, or one less cache line. There's no point in moving anything now because forthcoming patches will arrange other parts. --- diff --git a/include/haproxy/guid-t.h b/include/haproxy/guid-t.h index 9eea355d1..f77d921b2 100644 --- a/include/haproxy/guid-t.h +++ b/include/haproxy/guid-t.h @@ -1,14 +1,15 @@ #ifndef _HAPROXY_GUID_T_H #define _HAPROXY_GUID_T_H -#include +#include #include /* Maximum GUID size excluding final '\0' */ #define GUID_MAX_LEN 127 struct guid_node { - struct ebpt_node node; /* attach point into GUID global tree */ + struct ceb_node node; /* attach point into GUID global tree */ + char *key; /* the key itself */ enum obj_type *obj_type; /* pointer to GUID obj owner */ }; diff --git a/include/haproxy/guid.h b/include/haproxy/guid.h index f57a21d76..585883472 100644 --- a/include/haproxy/guid.h +++ b/include/haproxy/guid.h @@ -17,7 +17,7 @@ struct guid_node *guid_lookup(const char *uid); */ static inline const char *guid_get(const struct guid_node *guid) { - return guid->node.key; + return guid->key; } int guid_is_valid_fmt(const char *uid, char **errmsg); diff --git a/src/counters.c b/src/counters.c index 8506e3b5b..1f6238c37 100644 --- a/src/counters.c +++ b/src/counters.c @@ -83,7 +83,7 @@ static int _counters_shared_prepare(struct counters_shared *shared, struct be_counters_shared *be_shared; int it = 0; - if (!guid->node.key || !shm_stats_file_hdr) + if (!guid->key || !shm_stats_file_hdr) shared->flags |= COUNTERS_SHARED_F_LOCAL; while (it < global.nbtgroups) { diff --git a/src/guid.c b/src/guid.c index 9f29cfec0..f26f53ea3 100644 --- a/src/guid.c +++ b/src/guid.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -9,15 +9,16 @@ #include /* GUID global tree */ -struct eb_root guid_tree = EB_ROOT_UNIQUE; +struct ceb_root *guid_tree = NULL; __decl_thread(HA_RWLOCK_T guid_lock); + +/* note: touched under the guid_lock */ static int _guid_count = 0; /* Initialize members. */ void guid_init(struct guid_node *guid) { - guid->node.key = NULL; - guid->node.node.leaf_p = NULL; + memset(guid, 0, sizeof(*guid)); } /* Insert into GUID global tree with key . Must only be called on @@ -30,7 +31,6 @@ int guid_insert(enum obj_type *objt, const char *uid, char **errmsg) { struct guid_node *guid = NULL; struct guid_node *dup; - struct ebpt_node *node; char *dup_name = NULL; if (!guid_is_valid_fmt(uid, errmsg)) @@ -55,16 +55,15 @@ int guid_insert(enum obj_type *objt, const char *uid, char **errmsg) return 0; } - guid->node.key = strdup(uid); - if (!guid->node.key) { + guid->key = strdup(uid); + if (!guid->key) { memprintf(errmsg, "key alloc failure"); goto err; } HA_RWLOCK_WRLOCK(GUID_LOCK, &guid_lock); - node = ebis_insert(&guid_tree, &guid->node); - if (node != &guid->node) { - dup = ebpt_entry(node, struct guid_node, node); + dup = cebuis_item_insert(&guid_tree, node, key, guid); + if (dup != guid) { HA_RWLOCK_WRUNLOCK(GUID_LOCK, &guid_lock); dup_name = guid_name(dup); memprintf(errmsg, "duplicate entry with %s", dup_name); @@ -79,10 +78,8 @@ int guid_insert(enum obj_type *objt, const char *uid, char **errmsg) err: if (guid) - ha_free(&guid->node.key); + ha_free(&guid->key); ha_free(&dup_name); - if (guid) - guid->node.key = NULL; /* so that we can check that guid is not in a tree */ return 1; } @@ -92,10 +89,10 @@ int guid_insert(enum obj_type *objt, const char *uid, char **errmsg) void guid_remove(struct guid_node *guid) { HA_RWLOCK_WRLOCK(GUID_LOCK, &guid_lock); - ebpt_delete(&guid->node); - if (guid->node.key) + if (guid->key) _guid_count--; - ha_free(&guid->node.key); + cebuis_item_delete(&guid_tree, node, key, guid); + ha_free(&guid->key); HA_RWLOCK_WRUNLOCK(GUID_LOCK, &guid_lock); } @@ -105,7 +102,6 @@ void guid_remove(struct guid_node *guid) */ struct guid_node *guid_lookup(const char *uid) { - struct ebpt_node *node = NULL; struct guid_node *guid = NULL; /* For now, guid_lookup() is only used during startup in single-thread @@ -114,10 +110,7 @@ struct guid_node *guid_lookup(const char *uid) */ BUG_ON(!(global.mode & MODE_STARTING)); - node = ebis_lookup(&guid_tree, uid); - if (node) - guid = ebpt_entry(node, struct guid_node, node); - + guid = cebuis_item_lookup(&guid_tree, node, key, uid, struct guid_node); return guid; } diff --git a/src/stats-file.c b/src/stats-file.c index 578646cd2..3e50f3588 100644 --- a/src/stats-file.c +++ b/src/stats-file.c @@ -65,10 +65,10 @@ int stats_dump_fields_file(struct buffer *out, } /* Skip objects without GUID. */ - if (!guid->node.key) + if (!guid->key) return 1; - chunk_appendf(out, "%s,", (char *)guid->node.key); + chunk_appendf(out, "%s,", (char *)guid->key); for (i = 0; i < stats_count; ++i) { /* Empty field for stats-file is used to skip its output,