blob: f3c2a731477e78c23ba466d2e63b5ab428474205 [file] [log] [blame]
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +02001#include <string.h>
2
Willy Tarreau8d2b7772020-05-27 10:58:19 +02003#include <import/eb32tree.h>
4#include <import/ebistree.h>
Willy Tarreau3afc4c42020-06-03 18:23:19 +02005#include <haproxy/dict.h>
Willy Tarreau5b9cde42020-06-11 08:33:02 +02006#include <haproxy/thread.h>
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +02007
8struct dict *new_dict(const char *name)
9{
10 struct dict *dict;
11
12 dict = malloc(sizeof *dict);
13 if (!dict)
14 return NULL;
15
16 dict->name = name;
17 dict->values = EB_ROOT_UNIQUE;
18 HA_RWLOCK_INIT(&dict->rwlock);
19
20 return dict;
21}
22
23/*
24 * Allocate a new dictionary entry with <s> as string value which is strdup()'ed.
25 * Returns the new allocated entry if succeeded, NULL if not.
26 */
27static struct dict_entry *new_dict_entry(char *s)
28{
29 struct dict_entry *de;
30
31 de = calloc(1, sizeof *de);
32 if (!de)
33 return NULL;
34
35 de->value.key = strdup(s);
36 if (!de->value.key)
37 goto err;
38
Frédéric Lécaille99de1d02019-06-07 10:58:20 +020039 de->len = strlen(s);
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020040 de->refcount = 1;
41
42 return de;
43
44 err:
Willy Tarreau61cfdf42021-02-20 10:46:51 +010045 ha_free(&de->value.key);
Frédéric Lécaille99de1d02019-06-07 10:58:20 +020046 de->len = 0;
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020047 free(de);
48 return NULL;
49}
50
51/*
52 * Release the memory allocated for <de> dictionary entry.
53 */
54static void free_dict_entry(struct dict_entry *de)
55{
56 de->refcount = 0;
Willy Tarreau61cfdf42021-02-20 10:46:51 +010057 ha_free(&de->value.key);
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020058 free(de);
59}
60
61/*
62 * Simple function to lookup dictionary entries with <s> as value.
63 */
64static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
65{
66 struct dict_entry *de;
67 struct ebpt_node *node;
68
69 de = NULL;
70 node = ebis_lookup(&d->values, s);
71 if (node)
72 de = container_of(node, struct dict_entry, value);
73
74 return de;
75}
76
77/*
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020078 * Insert an entry in <d> dictionary with <s> as value. *
79 */
80struct dict_entry *dict_insert(struct dict *d, char *s)
81{
82 struct dict_entry *de;
Frédéric Lécailleb5ecf032019-06-11 08:34:26 +020083 struct ebpt_node *n;
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020084
85 HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
86 de = __dict_lookup(d, s);
87 HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
Thayne McCombs92149f92020-11-20 01:28:26 -070088 if (de) {
89 HA_ATOMIC_ADD(&de->refcount, 1);
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020090 return de;
Thayne McCombs92149f92020-11-20 01:28:26 -070091 }
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020092
93 de = new_dict_entry(s);
94 if (!de)
95 return NULL;
96
97 HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
Frédéric Lécailleb5ecf032019-06-11 08:34:26 +020098 n = ebis_insert(&d->values, &de->value);
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020099 HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
Frédéric Lécailleb5ecf032019-06-11 08:34:26 +0200100 if (n != &de->value) {
101 free_dict_entry(de);
102 de = container_of(n, struct dict_entry, value);
103 }
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +0200104
105 return de;
106}
107
Thayne McCombs92149f92020-11-20 01:28:26 -0700108
109/*
110 * Unreference a dict entry previously acquired with <dict_insert>.
111 * If this is the last live reference to the entry, it is
112 * removed from the dictionary.
113 */
114void dict_entry_unref(struct dict *d, struct dict_entry *de)
115{
116 if (!de)
117 return;
118
119 if (HA_ATOMIC_SUB(&de->refcount, 1) != 0)
120 return;
121
122 HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
123 ebpt_delete(&de->value);
124 HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
125
126 free_dict_entry(de);
127}