Line | Count | Source |
1 | | #include <string.h> |
2 | | |
3 | | #include <import/eb32tree.h> |
4 | | #include <import/ebistree.h> |
5 | | #include <haproxy/dict.h> |
6 | | #include <haproxy/thread.h> |
7 | | |
8 | | struct dict *new_dict(const char *name) |
9 | 0 | { |
10 | 0 | struct dict *dict; |
11 | |
|
12 | 0 | dict = malloc(sizeof *dict); |
13 | 0 | if (!dict) |
14 | 0 | return NULL; |
15 | | |
16 | 0 | dict->name = name; |
17 | 0 | dict->values = EB_ROOT_UNIQUE; |
18 | 0 | HA_RWLOCK_INIT(&dict->rwlock); |
19 | |
|
20 | 0 | return dict; |
21 | 0 | } |
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 | | */ |
27 | | static struct dict_entry *new_dict_entry(char *s) |
28 | 0 | { |
29 | 0 | struct dict_entry *de; |
30 | |
|
31 | 0 | de = calloc(1, sizeof *de); |
32 | 0 | if (!de) |
33 | 0 | return NULL; |
34 | | |
35 | 0 | de->value.key = strdup(s); |
36 | 0 | if (!de->value.key) |
37 | 0 | goto err; |
38 | | |
39 | 0 | de->len = strlen(s); |
40 | 0 | de->refcount = 1; |
41 | |
|
42 | 0 | return de; |
43 | | |
44 | 0 | err: |
45 | 0 | ha_free(&de->value.key); |
46 | 0 | de->len = 0; |
47 | 0 | free(de); |
48 | 0 | return NULL; |
49 | 0 | } |
50 | | |
51 | | /* |
52 | | * Release the memory allocated for <de> dictionary entry. |
53 | | */ |
54 | | static void free_dict_entry(struct dict_entry *de) |
55 | 0 | { |
56 | 0 | de->refcount = 0; |
57 | 0 | ha_free(&de->value.key); |
58 | 0 | free(de); |
59 | 0 | } |
60 | | |
61 | | /* |
62 | | * Simple function to lookup dictionary entries with <s> as value. |
63 | | */ |
64 | | static struct dict_entry *__dict_lookup(struct dict *d, const char *s) |
65 | 0 | { |
66 | 0 | struct dict_entry *de; |
67 | 0 | struct ebpt_node *node; |
68 | |
|
69 | 0 | de = NULL; |
70 | 0 | node = ebis_lookup(&d->values, s); |
71 | 0 | if (node) |
72 | 0 | de = container_of(node, struct dict_entry, value); |
73 | |
|
74 | 0 | return de; |
75 | 0 | } |
76 | | |
77 | | /* |
78 | | * Insert an entry in <d> dictionary with <s> as value. * |
79 | | */ |
80 | | struct dict_entry *dict_insert(struct dict *d, char *s) |
81 | 0 | { |
82 | 0 | struct dict_entry *de; |
83 | 0 | struct ebpt_node *n; |
84 | |
|
85 | 0 | HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock); |
86 | 0 | de = __dict_lookup(d, s); |
87 | 0 | HA_RWLOCK_RDUNLOCK(DICT_LOCK, &d->rwlock); |
88 | 0 | if (de) { |
89 | 0 | HA_ATOMIC_INC(&de->refcount); |
90 | 0 | return de; |
91 | 0 | } |
92 | | |
93 | 0 | de = new_dict_entry(s); |
94 | 0 | if (!de) |
95 | 0 | return NULL; |
96 | | |
97 | 0 | HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock); |
98 | 0 | n = ebis_insert(&d->values, &de->value); |
99 | 0 | HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock); |
100 | 0 | if (n != &de->value) { |
101 | 0 | free_dict_entry(de); |
102 | 0 | de = container_of(n, struct dict_entry, value); |
103 | 0 | } |
104 | |
|
105 | 0 | return de; |
106 | 0 | } |
107 | | |
108 | | |
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 | | */ |
114 | | void dict_entry_unref(struct dict *d, struct dict_entry *de) |
115 | 0 | { |
116 | 0 | if (!de) |
117 | 0 | return; |
118 | | |
119 | 0 | if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0) |
120 | 0 | return; |
121 | | |
122 | 0 | HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock); |
123 | 0 | ebpt_delete(&de->value); |
124 | 0 | HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock); |
125 | |
|
126 | 0 | free_dict_entry(de); |
127 | 0 | } |