]> arthur.barton.de Git - netdata.git/blob - src/dictionary.c
work in progress: registry
[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                 pthread_rwlock_rdlock(&dict->rwlock);
42 }
43
44 static void dictionary_write_lock(DICTIONARY *dict) {
45         if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED)))
46                 pthread_rwlock_wrlock(&dict->rwlock);
47 }
48
49 static void dictionary_unlock(DICTIONARY *dict) {
50         if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED)))
51                 pthread_rwlock_unlock(&dict->rwlock);
52 }
53
54 // ----------------------------------------------------------------------------
55
56 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
57         debug(D_DICTIONARY, "Creating name value entry for name '%s', value '%s'.", name, value);
58
59         NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
60         if(unlikely(!nv)) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
61
62         if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
63                 nv->name = (char *)name;
64         else {
65                 nv->name = strdup(name);
66                 if (unlikely(!nv->name))
67                         fatal("Cannot allocate name_value.name of size %z", strlen(name));
68         }
69
70         nv->hash = (hash)?hash:simple_hash(nv->name);
71
72         if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
73                 nv->value = value;
74         else {
75                 nv->value = malloc(value_len);
76                 if (unlikely(!nv->value))
77                         fatal("Cannot allocate name_value.value of size %z", value_len);
78
79                 memcpy(nv->value, value, value_len);
80         }
81
82         dictionary_write_lock(dict);
83
84         // index it
85         dictionary_name_value_index_add_nolock(dict, nv);
86
87         dict->entries++;
88
89         dictionary_unlock(dict);
90
91         return nv;
92 }
93
94 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
95         debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
96
97         dictionary_name_value_index_del_nolock(dict, nv);
98
99         dict->entries--;
100
101         free(nv->name);
102
103         if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE))
104                 free(nv->value);
105
106         free(nv);
107 }
108
109 // ----------------------------------------------------------------------------
110
111 DICTIONARY *dictionary_create(uint32_t flags) {
112         debug(D_DICTIONARY, "Creating dictionary.");
113
114         DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
115         if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY");
116
117         avl_init(&dict->values_index, name_value_compare);
118         pthread_rwlock_init(&dict->rwlock, NULL);
119
120         dict->flags = flags;
121
122         return dict;
123 }
124
125 void dictionary_destroy(DICTIONARY *dict) {
126         debug(D_DICTIONARY, "Destroying dictionary.");
127
128         dictionary_write_lock(dict);
129
130         while(dict->values_index.root)
131                 dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
132
133         dictionary_unlock(dict);
134
135         free(dict);
136 }
137
138 // ----------------------------------------------------------------------------
139
140 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
141         debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
142
143         uint32_t hash = simple_hash(name);
144
145         dictionary_read_lock(dict);
146         NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
147         dictionary_unlock(dict);
148
149         if(unlikely(!nv)) {
150                 debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
151
152                 pthread_rwlock_wrlock(&dict->rwlock);
153                 nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
154
155                 if(unlikely(!nv))
156                         fatal("Cannot create name_value.");
157
158                 dictionary_unlock(dict);
159         }
160         else {
161                 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
162
163                 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
164                         nv->value = value;
165                 else {
166                         void *value = malloc(value_len),
167                                         *old = nv->value;
168
169                         if(unlikely(!nv->value))
170                                 fatal("Cannot allocate value of size %z", value_len);
171
172                         memcpy(value, value, value_len);
173                         nv->value = value;
174
175                         free(old);
176                 }
177         }
178
179         return nv->value;
180 }
181
182 void *dictionary_get(DICTIONARY *dict, const char *name) {
183         debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
184
185         dictionary_read_lock(dict);
186         NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
187         dictionary_unlock(dict);
188
189         if(unlikely(!nv)) {
190                 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
191                 return NULL;
192         }
193
194         debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
195         return nv->value;
196 }
197
198 void dictionary_del(DICTIONARY *dict, const char *name) {
199         debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
200
201         dictionary_read_lock(dict);
202         NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
203         dictionary_unlock(dict);
204
205         if(unlikely(!nv)) {
206                 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
207                 return;
208         }
209
210         debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
211         pthread_rwlock_wrlock(&dict->rwlock);
212         dictionary_name_value_destroy_nolock(dict, nv);
213         dictionary_unlock(dict);
214 }