diff options
Diffstat (limited to 'src/dict.c')
-rw-r--r-- | src/dict.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/dict.c b/src/dict.c new file mode 100644 index 0000000..a225081 --- /dev/null +++ b/src/dict.c @@ -0,0 +1,127 @@ +#include <string.h> + +#include <import/eb32tree.h> +#include <import/ebistree.h> +#include <haproxy/dict.h> +#include <haproxy/thread.h> + +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 <s> 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->len = strlen(s); + de->refcount = 1; + + return de; + + err: + ha_free(&de->value.key); + de->len = 0; + free(de); + return NULL; +} + +/* + * Release the memory allocated for <de> dictionary entry. + */ +static void free_dict_entry(struct dict_entry *de) +{ + de->refcount = 0; + ha_free(&de->value.key); + free(de); +} + +/* + * Simple function to lookup dictionary entries with <s> 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 an entry in <d> dictionary with <s> as value. * + */ +struct dict_entry *dict_insert(struct dict *d, char *s) +{ + struct dict_entry *de; + struct ebpt_node *n; + + HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock); + de = __dict_lookup(d, s); + HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock); + if (de) { + HA_ATOMIC_INC(&de->refcount); + return de; + } + + de = new_dict_entry(s); + if (!de) + return NULL; + + HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock); + n = ebis_insert(&d->values, &de->value); + HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock); + if (n != &de->value) { + free_dict_entry(de); + de = container_of(n, struct dict_entry, value); + } + + return de; +} + + +/* + * Unreference a dict entry previously acquired with <dict_insert>. + * If this is the last live reference to the entry, it is + * removed from the dictionary. + */ +void dict_entry_unref(struct dict *d, struct dict_entry *de) +{ + if (!de) + return; + + if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0) + return; + + HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock); + ebpt_delete(&de->value); + HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock); + + free_dict_entry(de); +} |