]> arthur.barton.de Git - netdata.git/blob - src/dictionary.c
registry progress: working internal prototype - no load/save and network yet
[netdata.git] / src / dictionary.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <pthread.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "avl.h"
10 #include "common.h"
11 #include "log.h"
12
13 #include "dictionary.h"
14
15 // ----------------------------------------------------------------------------
16 // name_value index
17
18 static int name_value_iterator(avl *a) { if(a) {}; return 0; }
19
20 static int name_value_compare(void* a, void* b) {
21         if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
22         else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
23         else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
24 }
25
26 #define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
27 #define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
28
29 static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
30         NAME_VALUE *result = NULL, tmp;
31         tmp.hash = (hash)?hash:simple_hash(name);
32         tmp.name = (char *)name;
33
34         dict->searches++;
35         avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
36         return result;
37 }
38
39 static void dictionary_read_lock(DICTIONARY *dict) {
40         if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
41                 // debug(D_DICTIONARY, "Dictionary READ lock");
42                 pthread_rwlock_rdlock(&dict->rwlock);
43         }
44 }
45
46 static void dictionary_write_lock(DICTIONARY *dict) {
47         if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
48                 // debug(D_DICTIONARY, "Dictionary WRITE lock");
49                 pthread_rwlock_wrlock(&dict->rwlock);
50         }
51 }
52
53 static void dictionary_unlock(DICTIONARY *dict) {
54         if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
55                 // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
56                 pthread_rwlock_unlock(&dict->rwlock);
57         }
58 }
59
60 // ----------------------------------------------------------------------------
61
62 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
63         debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
64
65         NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
66         if(unlikely(!nv)) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
67
68         if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
69                 nv->name = (char *)name;
70         else {
71                 nv->name = strdup(name);
72                 if (unlikely(!nv->name))
73                         fatal("Cannot allocate name_value.name of size %z", strlen(name));
74         }
75
76         nv->hash = (hash)?hash:simple_hash(nv->name);
77
78         if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
79                 nv->value = value;
80         else {
81                 nv->value = malloc(value_len);
82                 if (unlikely(!nv->value))
83                         fatal("Cannot allocate name_value.value of size %z", value_len);
84
85                 memcpy(nv->value, value, value_len);
86         }
87
88         // index it
89         dictionary_name_value_index_add_nolock(dict, nv);
90         dict->entries++;
91
92         return nv;
93 }
94
95 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
96         debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
97
98         dictionary_name_value_index_del_nolock(dict, nv);
99
100         dict->entries--;
101
102         if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
103                 debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
104                 free(nv->value);
105         }
106
107         if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
108                 debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
109                 free(nv->name);
110         }
111
112         free(nv);
113 }
114
115 // ----------------------------------------------------------------------------
116
117 DICTIONARY *dictionary_create(uint32_t flags) {
118         debug(D_DICTIONARY, "Creating dictionary.");
119
120         DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
121         if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY");
122
123         avl_init(&dict->values_index, name_value_compare);
124         pthread_rwlock_init(&dict->rwlock, NULL);
125
126         dict->flags = flags;
127
128         return dict;
129 }
130
131 void dictionary_destroy(DICTIONARY *dict) {
132         debug(D_DICTIONARY, "Destroying dictionary.");
133
134         dictionary_write_lock(dict);
135
136         while(dict->values_index.root)
137                 dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
138
139         dictionary_unlock(dict);
140
141         free(dict);
142 }
143
144 // ----------------------------------------------------------------------------
145
146 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
147         debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
148
149         uint32_t hash = simple_hash(name);
150
151         dictionary_read_lock(dict);
152         NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
153         dictionary_unlock(dict);
154
155         if(unlikely(!nv)) {
156                 debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
157
158                 dictionary_write_lock(dict);
159                 nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
160                 dictionary_unlock(dict);
161
162                 if(unlikely(!nv))
163                         fatal("Cannot create name_value.");
164         }
165         else {
166                 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
167
168                 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
169                         debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
170                         nv->value = value;
171                 }
172                 else {
173                         debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
174
175                         void *value = malloc(value_len),
176                                         *old = nv->value;
177
178                         if(unlikely(!nv->value))
179                                 fatal("Cannot allocate value of size %z", value_len);
180
181                         memcpy(value, value, value_len);
182                         nv->value = value;
183
184                         debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
185                         free(old);
186                 }
187         }
188
189         return nv->value;
190 }
191
192 void *dictionary_get(DICTIONARY *dict, const char *name) {
193         debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
194
195         dictionary_read_lock(dict);
196         NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
197         dictionary_unlock(dict);
198
199         if(unlikely(!nv)) {
200                 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
201                 return NULL;
202         }
203
204         debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
205         return nv->value;
206 }
207
208 int dictionary_del(DICTIONARY *dict, const char *name) {
209         debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
210
211         dictionary_read_lock(dict);
212         NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
213         dictionary_unlock(dict);
214
215         if(unlikely(!nv)) {
216                 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
217                 return -1;
218         }
219
220         debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
221         dictionary_write_lock(dict);
222         dictionary_name_value_destroy_nolock(dict, nv);
223         dictionary_unlock(dict);
224
225         return 0;
226 }
227
228
229 static void dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
230         if(unlikely(!a)) return;
231
232         if(a->right)
233                 dictionary_walker(a->right, callback, data);
234
235         callback(((NAME_VALUE *)a)->value, data);
236
237         if(a->left)
238                 dictionary_walker(a->left, callback, data);
239 }
240
241 void dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) {
242         dictionary_read_lock(dict);
243         dictionary_walker(dict->values_index.root, callback, data);
244         dictionary_unlock(dict);
245 }