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