diff --git a/include/haproxy/vars-t.h b/include/haproxy/vars-t.h index 320c7d6831ed..3ad8c73ac6ae 100644 --- a/include/haproxy/vars-t.h +++ b/include/haproxy/vars-t.h @@ -24,6 +24,7 @@ #include #include +#include /* flags used when setting/clearing variables */ #define VF_CREATEONLY 0x00000001 // do nothing if the variable already exists @@ -48,7 +49,7 @@ enum vars_scope { }; struct vars { - struct list head; + struct ceb_node *name_root; enum vars_scope scope; unsigned int size; __decl_thread(HA_RWLOCK_T rwlock); @@ -64,8 +65,8 @@ struct var_desc { }; struct var { - struct list l; /* Used for chaining vars. */ - uint64_t name_hash; /* XXH3() of the variable's name */ + struct ceb_node node; /* Used for chaining vars. */ + uint64_t name_hash; /* XXH3() of the variable's name, must be just after node */ uint flags; // VF_* /* 32-bit hole here */ struct sample_data data; /* data storage. */ diff --git a/include/haproxy/vars.h b/include/haproxy/vars.h index 95bb4dcd80c1..86dcf2d46ef1 100644 --- a/include/haproxy/vars.h +++ b/include/haproxy/vars.h @@ -22,6 +22,8 @@ #ifndef _HAPROXY_VARS_H #define _HAPROXY_VARS_H +#include + #include #include #include @@ -34,7 +36,7 @@ struct arg; void vars_init_head(struct vars *vars, enum vars_scope scope); void var_accounting_diff(struct vars *vars, struct session *sess, struct stream *strm, int size); -unsigned int var_clear(struct var *var, int force); +unsigned int var_clear(struct vars *vars, struct var *var, int force); void vars_prune_per_sess(struct vars *vars); int var_set(const struct var_desc *desc, struct sample *smp, uint flags); int var_unset(const struct var_desc *desc, struct sample *smp); @@ -78,11 +80,13 @@ static inline void vars_rdunlock(struct vars *vars) */ static inline void vars_prune(struct vars *vars, struct session *sess, struct stream *strm) { - struct var *var, *tmp; + struct ceb_node *node; + struct var *var; unsigned int size = 0; - list_for_each_entry_safe(var, tmp, &vars->head, l) { - size += var_clear(var, 1); + while ((node = cebu64_first(&vars->name_root))) { + var = container_of(node, struct var, node); + size += var_clear(vars, var, 1); } if (!size) diff --git a/src/vars.c b/src/vars.c index 0c34202e6fc0..6ba82b7e05c0 100644 --- a/src/vars.c +++ b/src/vars.c @@ -20,6 +20,8 @@ #include #include +#include + /* This contains a pool of struct vars */ DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var)); @@ -172,7 +174,7 @@ static int var_accounting_add(struct vars *vars, struct session *sess, struct st * using. If the variable is marked "VF_PERMANENT", the sample_data is only * reset to SMP_T_ANY unless is non nul. Returns the freed size. */ -unsigned int var_clear(struct var *var, int force) +unsigned int var_clear(struct vars *vars, struct var *var, int force) { unsigned int size = 0; @@ -188,7 +190,7 @@ unsigned int var_clear(struct var *var, int force) var->data.type = SMP_T_ANY; if (!(var->flags & VF_PERMANENT) || force) { - LIST_DELETE(&var->l); + cebu64_delete(&vars->name_root, &var->node); pool_free(var_pool, var); size += sizeof(struct var); } @@ -200,11 +202,13 @@ unsigned int var_clear(struct var *var, int force) */ void vars_prune_per_sess(struct vars *vars) { - struct var *var, *tmp; + struct ceb_node *node; + struct var *var; unsigned int size = 0; - list_for_each_entry_safe(var, tmp, &vars->head, l) { - size += var_clear(var, 1); + while ((node = cebu64_first(&vars->name_root))) { + var = container_of(node, struct var, node); + size += var_clear(vars, var, 1); } if (!size) @@ -219,7 +223,7 @@ void vars_prune_per_sess(struct vars *vars) /* This function initializes a variables list head */ void vars_init_head(struct vars *vars, enum vars_scope scope) { - LIST_INIT(&vars->head); + vars->name_root = NULL; vars->scope = scope; vars->size = 0; HA_RWLOCK_INIT(&vars->rwlock); @@ -327,11 +331,12 @@ static int vars_fill_desc(const char *name, int len, struct var_desc *desc, char */ static struct var *var_get(struct vars *vars, uint64_t name_hash) { - struct var *var; + struct ceb_node *node; + + node = cebu64_lookup(&vars->name_root, name_hash); + if (node) + return container_of(node, struct var, node); - list_for_each_entry(var, &vars->head, l) - if (var->name_hash == name_hash) - return var; return NULL; } @@ -428,10 +433,10 @@ int var_set(const struct var_desc *desc, struct sample *smp, uint flags) var = pool_alloc(var_pool); if (!var) goto unlock; - LIST_APPEND(&vars->head, &var->l); var->name_hash = desc->name_hash; var->flags = flags & VF_PERMANENT; var->data.type = SMP_T_ANY; + cebu64_insert(&vars->name_root, &var->node); } /* A variable of type SMP_T_ANY is considered as unset (either created @@ -561,7 +566,7 @@ int var_unset(const struct var_desc *desc, struct sample *smp) vars_wrlock(vars); var = var_get(vars, desc->name_hash); if (var) { - size = var_clear(var, 0); + size = var_clear(vars, var, 0); var_accounting_diff(vars, smp->sess, smp->strm, -size); } vars_wrunlock(vars);