13 #include "dictionary.h"
15 // ----------------------------------------------------------------------------
18 static int name_value_iterator(avl *a) { if(a) {}; return 0; }
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);
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)
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;
35 avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
40 static void dictionary_read_lock(DICTIONARY *dict) {
41 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
42 // debug(D_DICTIONARY, "Dictionary READ lock");
43 pthread_rwlock_rdlock(&dict->rwlock);
47 static void dictionary_write_lock(DICTIONARY *dict) {
48 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
49 // debug(D_DICTIONARY, "Dictionary WRITE lock");
50 pthread_rwlock_wrlock(&dict->rwlock);
54 static void dictionary_unlock(DICTIONARY *dict) {
55 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
56 // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
57 pthread_rwlock_unlock(&dict->rwlock);
61 // ----------------------------------------------------------------------------
63 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
64 debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
66 NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
67 if(unlikely(!nv)) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
69 if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
70 nv->name = (char *)name;
72 nv->name = strdup(name);
73 if (unlikely(!nv->name))
74 fatal("Cannot allocate name_value.name of size %z", strlen(name));
77 nv->hash = (hash)?hash:simple_hash(nv->name);
79 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
82 nv->value = malloc(value_len);
83 if (unlikely(!nv->value))
84 fatal("Cannot allocate name_value.value of size %z", value_len);
86 memcpy(nv->value, value, value_len);
90 dictionary_name_value_index_add_nolock(dict, nv);
96 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
97 debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
99 dictionary_name_value_index_del_nolock(dict, nv);
103 if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
104 debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
108 if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
109 debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
116 // ----------------------------------------------------------------------------
118 DICTIONARY *dictionary_create(uint32_t flags) {
119 debug(D_DICTIONARY, "Creating dictionary.");
121 DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
122 if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY");
124 avl_init(&dict->values_index, name_value_compare);
125 pthread_rwlock_init(&dict->rwlock, NULL);
132 void dictionary_destroy(DICTIONARY *dict) {
133 debug(D_DICTIONARY, "Destroying dictionary.");
135 dictionary_write_lock(dict);
137 while(dict->values_index.root)
138 dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
140 dictionary_unlock(dict);
145 // ----------------------------------------------------------------------------
147 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
148 debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
150 uint32_t hash = simple_hash(name);
152 dictionary_read_lock(dict);
153 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
154 dictionary_unlock(dict);
157 debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
159 dictionary_write_lock(dict);
160 nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
161 dictionary_unlock(dict);
164 fatal("Cannot create name_value.");
167 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
169 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
170 debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
174 debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
176 void *value = malloc(value_len),
179 if(unlikely(!nv->value))
180 fatal("Cannot allocate value of size %z", value_len);
182 memcpy(value, value, value_len);
185 debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
193 void *dictionary_get(DICTIONARY *dict, const char *name) {
194 debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
196 dictionary_read_lock(dict);
197 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
198 dictionary_unlock(dict);
201 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
205 debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
209 int dictionary_del(DICTIONARY *dict, const char *name) {
210 debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
212 dictionary_read_lock(dict);
213 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
214 dictionary_unlock(dict);
217 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
221 debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
222 dictionary_write_lock(dict);
223 dictionary_name_value_destroy_nolock(dict, nv);
224 dictionary_unlock(dict);
230 static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
231 int total = 0, ret = 0;
234 ret = dictionary_walker(a->right, callback, data);
235 if(ret < 0) return ret;
239 ret = callback(((NAME_VALUE *)a)->value, data);
240 if(ret < 0) return ret;
244 dictionary_walker(a->left, callback, data);
245 if (ret < 0) return ret;
252 int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) {
255 dictionary_read_lock(dict);
257 if(likely(dict->values_index.root))
258 ret = dictionary_walker(dict->values_index.root, callback, data);
260 dictionary_unlock(dict);