blob: 9b3536d96e926092f50f16acfeca91b64bd08ba2 [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:
45 free(de->value.key);
46 de->value.key = NULL;
Frédéric Lécaille99de1d02019-06-07 10:58:20 +020047 de->len = 0;
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020048 free(de);
49 return NULL;
50}
51
52/*
53 * Release the memory allocated for <de> dictionary entry.
54 */
55static void free_dict_entry(struct dict_entry *de)
56{
57 de->refcount = 0;
58 free(de->value.key);
59 de->value.key = NULL;
60 free(de);
61}
62
63/*
64 * Simple function to lookup dictionary entries with <s> as value.
65 */
66static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
67{
68 struct dict_entry *de;
69 struct ebpt_node *node;
70
71 de = NULL;
72 node = ebis_lookup(&d->values, s);
73 if (node)
74 de = container_of(node, struct dict_entry, value);
75
76 return de;
77}
78
79/*
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020080 * Insert an entry in <d> dictionary with <s> as value. *
81 */
82struct dict_entry *dict_insert(struct dict *d, char *s)
83{
84 struct dict_entry *de;
Frédéric Lécailleb5ecf032019-06-11 08:34:26 +020085 struct ebpt_node *n;
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020086
87 HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
88 de = __dict_lookup(d, s);
89 HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock);
Thayne McCombs92149f92020-11-20 01:28:26 -070090 if (de) {
91 HA_ATOMIC_ADD(&de->refcount, 1);
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020092 return de;
Thayne McCombs92149f92020-11-20 01:28:26 -070093 }
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +020094
95 de = new_dict_entry(s);
96 if (!de)
97 return NULL;
98
99 HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
Frédéric Lécailleb5ecf032019-06-11 08:34:26 +0200100 n = ebis_insert(&d->values, &de->value);
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +0200101 HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
Frédéric Lécailleb5ecf032019-06-11 08:34:26 +0200102 if (n != &de->value) {
103 free_dict_entry(de);
104 de = container_of(n, struct dict_entry, value);
105 }
Frédéric Lécaille4a3fef82019-05-28 14:47:17 +0200106
107 return de;
108}
109
Thayne McCombs92149f92020-11-20 01:28:26 -0700110
111/*
112 * Unreference a dict entry previously acquired with <dict_insert>.
113 * If this is the last live reference to the entry, it is
114 * removed from the dictionary.
115 */
116void dict_entry_unref(struct dict *d, struct dict_entry *de)
117{
118 if (!de)
119 return;
120
121 if (HA_ATOMIC_SUB(&de->refcount, 1) != 0)
122 return;
123
124 HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
125 ebpt_delete(&de->value);
126 HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
127
128 free_dict_entry(de);
129}