]> arthur.barton.de Git - netdata.git/blob - src/dictionary.c
74d58920befae76ea34220e5c7f24730a0de53af
[netdata.git] / src / dictionary.c
1 #include <pthread.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5
6 #include "avl.h"
7 #include "common.h"
8 #include "log.h"
9
10 #include "dictionary.h"
11
12 // ----------------------------------------------------------------------------
13 // name_value index
14
15 static int name_value_iterator(avl *a) { if(a) {}; return 0; }
16
17 static int name_value_compare(void* a, void* b) {
18         if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
19         else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
20         else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
21 }
22
23 #define name_value_index_add(dict, cv) avl_insert(&((dict)->values_index), (avl *)(cv))
24 #define name_value_index_del(dict, cv) avl_remove(&((dict)->values_index), (avl *)(cv))
25
26 static NAME_VALUE *dictionary_name_value_index_find(DICTIONARY *dict, const char *name, uint32_t hash) {
27         NAME_VALUE *result = NULL, tmp;
28         tmp.hash = (hash)?hash:simple_hash(name);
29         tmp.name = (char *)name;
30
31         avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
32         return result;
33 }
34
35 // ----------------------------------------------------------------------------
36
37 static NAME_VALUE *dictionary_name_value_create(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
38         debug(D_DICTIONARY, "Creating name value entry for name '%s', value '%s'.", name, value);
39
40         NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
41         if(!nv) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
42
43         nv->name = strdup(name);
44         if(!nv->name) fatal("Cannot allocate name_value.name of size %z", strlen(name));
45         nv->hash = simple_hash(nv->name);
46
47         nv->value = malloc(value_len);
48         if(!nv->value) fatal("Cannot allocate name_value.value of size %z", value_len);
49         memcpy(nv->value, value, value_len);
50
51         // link it
52         pthread_rwlock_wrlock(&dict->rwlock);
53         nv->next = dict->values;
54         dict->values = nv;
55         pthread_rwlock_unlock(&dict->rwlock);
56
57         // index it
58         name_value_index_add(dict, nv);
59
60         return nv;
61 }
62
63 static void dictionary_name_value_destroy(DICTIONARY *dict, NAME_VALUE *nv) {
64         debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
65
66         pthread_rwlock_wrlock(&dict->rwlock);
67         if(dict->values == nv) dict->values = nv->next;
68         else {
69                 NAME_VALUE *n = dict->values;
70                 while(n && n->next && n->next != nv) nv = nv->next;
71                 if(!n || n->next != nv) fatal("Cannot find name_value with name '%s' in dictionary.", nv->name);
72                 n->next = nv->next;
73                 nv->next = NULL;
74         }
75         pthread_rwlock_unlock(&dict->rwlock);
76
77         free(nv->value);
78         free(nv);
79 }
80
81 // ----------------------------------------------------------------------------
82
83 DICTIONARY *dictionary_create(void) {
84         debug(D_DICTIONARY, "Creating dictionary.");
85
86         DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
87         if(!dict) fatal("Cannot allocate DICTIONARY");
88
89         dict->values_index.compar = name_value_compare;
90         pthread_rwlock_init(&dict->rwlock, NULL);
91
92         return dict;
93 }
94
95 void dictionary_destroy(DICTIONARY *dict) {
96         debug(D_DICTIONARY, "Destroying dictionary.");
97
98         pthread_rwlock_wrlock(&dict->rwlock);
99         while(dict->values) dictionary_name_value_destroy(dict, dict->values);
100         pthread_rwlock_unlock(&dict->rwlock);
101
102         free(dict);
103 }
104
105 // ----------------------------------------------------------------------------
106
107 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
108         debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
109
110         pthread_rwlock_rdlock(&dict->rwlock);
111         NAME_VALUE *nv = dictionary_name_value_index_find(dict, name, 0);
112         pthread_rwlock_unlock(&dict->rwlock);
113         if(!nv) {
114                 debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
115                 nv = dictionary_name_value_create(dict, name, value, value_len);
116                 if(!nv) fatal("Cannot create name_value.");
117                 return nv->value;
118         }
119         else {
120                 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
121                 pthread_rwlock_wrlock(&dict->rwlock);
122                 void *old = nv->value;
123                 nv->value = malloc(value_len);
124                 if(!nv->value) fatal("Cannot allocate value of size %z", value_len);
125                 memcpy(nv->value, value, value_len);
126                 pthread_rwlock_unlock(&dict->rwlock);
127                 free(old);
128         }
129
130         return nv->value;
131 }
132
133 void *dictionary_get(DICTIONARY *dict, const char *name) {
134         debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
135
136         pthread_rwlock_rdlock(&dict->rwlock);
137         NAME_VALUE *nv = dictionary_name_value_index_find(dict, name, 0);
138         pthread_rwlock_unlock(&dict->rwlock);
139         if(!nv) {
140                 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
141                 return NULL;
142         }
143
144         debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
145         return nv->value;
146 }