From: Frédéric Lécaille Date: Tue, 28 May 2019 12:47:17 +0000 (+0200) Subject: MINOR: dict: Add dictionary new data structure. X-Git-Tag: v2.0-dev6~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a3fef834c532affb1c9ba80717bb930a919d32b;p=thirdparty%2Fhaproxy.git MINOR: dict: Add dictionary new data structure. This patch adds minimalistic definitions to implement dictionary new data structure which is an ebtree of ebpt_node structs with strings as keys. Note that this has nothing to see with real dictionary data structure (maps of keys in association with values). --- diff --git a/Makefile b/Makefile index cf4a3d9e69..66959741d2 100644 --- a/Makefile +++ b/Makefile @@ -788,7 +788,7 @@ OBJS = src/proto_http.o src/cfgparse-listen.o src/proto_htx.o src/stream.o \ src/xxhash.o src/hpack-enc.o src/h2.o src/freq_ctr.o src/lru.o \ src/protocol.o src/arg.o src/hpack-huff.o src/hdr_idx.o src/base64.o \ src/hash.o src/mailers.o src/activity.o src/http_msg.o src/version.o \ - src/mworker.o src/mworker-prog.o src/debug.o src/wdt.o + src/mworker.o src/mworker-prog.o src/debug.o src/wdt.o src/dict.o EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o $(EBTREE_DIR)/eb32sctree.o \ $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \ diff --git a/include/common/hathreads.h b/include/common/hathreads.h index 0ba56d0d00..79a6466364 100644 --- a/include/common/hathreads.h +++ b/include/common/hathreads.h @@ -547,6 +547,7 @@ enum lock_label { TLSKEYS_REF_LOCK, AUTH_LOCK, LOGSRV_LOCK, + DICT_LOCK, OTHER_LOCK, LOCK_LABELS }; @@ -663,6 +664,7 @@ static inline const char *lock_label(enum lock_label label) case TLSKEYS_REF_LOCK: return "TLSKEYS_REF"; case AUTH_LOCK: return "AUTH"; case LOGSRV_LOCK: return "LOGSRV"; + case DICT_LOCK: return "DICT"; case OTHER_LOCK: return "OTHER"; case LOCK_LABELS: break; /* keep compiler happy */ }; diff --git a/include/proto/dict.h b/include/proto/dict.h new file mode 100644 index 0000000000..26f48decb4 --- /dev/null +++ b/include/proto/dict.h @@ -0,0 +1,9 @@ +#ifndef _PROTO_DICT_H +#define _PROTO_DICT_H + +#include + +struct dict *new_dict(const char *name); +struct dict_entry *dict_insert(struct dict *d, char *str); + +#endif /* _PROTO_DICT_H */ diff --git a/include/types/dict.h b/include/types/dict.h new file mode 100644 index 0000000000..9e4f41a68b --- /dev/null +++ b/include/types/dict.h @@ -0,0 +1,18 @@ +#ifndef _TYPES_DICT_H +#define _TYPES_DICT_H + +#include +#include + +struct dict_entry { + struct ebpt_node value; + unsigned int refcount; +}; + +struct dict { + const char *name; + struct eb_root values; + __decl_hathreads(HA_RWLOCK_T rwlock); +}; + +#endif /* _TYPES_DICT_H */ diff --git a/src/dict.c b/src/dict.c new file mode 100644 index 0000000000..777530a20c --- /dev/null +++ b/src/dict.c @@ -0,0 +1,118 @@ +#include + +#include + +#include +#include + +struct dict *new_dict(const char *name) +{ + struct dict *dict; + + dict = malloc(sizeof *dict); + if (!dict) + return NULL; + + dict->name = name; + dict->values = EB_ROOT_UNIQUE; + HA_RWLOCK_INIT(&dict->rwlock); + + return dict; +} + +/* + * Allocate a new dictionary entry with as string value which is strdup()'ed. + * Returns the new allocated entry if succeeded, NULL if not. + */ +static struct dict_entry *new_dict_entry(char *s) +{ + struct dict_entry *de; + + de = calloc(1, sizeof *de); + if (!de) + return NULL; + + de->value.key = strdup(s); + if (!de->value.key) + goto err; + + de->refcount = 1; + + return de; + + err: + free(de->value.key); + de->value.key = NULL; + free(de); + return NULL; +} + +/* + * Release the memory allocated for dictionary entry. + */ +static void free_dict_entry(struct dict_entry *de) +{ + de->refcount = 0; + free(de->value.key); + de->value.key = NULL; + free(de); +} + +/* + * Simple function to lookup dictionary entries with as value. + */ +static struct dict_entry *__dict_lookup(struct dict *d, const char *s) +{ + struct dict_entry *de; + struct ebpt_node *node; + + de = NULL; + node = ebis_lookup(&d->values, s); + if (node) + de = container_of(node, struct dict_entry, value); + + return de; +} + +/* + * Insert node in ebtree, deleting any already existing node with + * the same value. + */ +static struct ebpt_node *__dict_insert(struct eb_root *root, struct ebpt_node *node) +{ + struct ebpt_node *n; + + n = ebis_insert(root, node); + if (n != node) { + ebpt_delete(n); + free_dict_entry(container_of(n, struct dict_entry, value)); + ebis_insert(root, node); + } + + return node; +} + +/* + * Insert an entry in dictionary with as value. * + */ +struct dict_entry *dict_insert(struct dict *d, char *s) +{ + struct dict_entry *de; + + HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock); + de = __dict_lookup(d, s); + HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock); + if (de) + return de; + + de = new_dict_entry(s); + if (!de) + return NULL; + + HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock); + __dict_insert(&d->values, &de->value); + HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock); + + return de; +} +