13 #include "dictionary.h"
15 // ----------------------------------------------------------------------------
18 static inline void dictionary_atomic_updates_lock(DICTIONARY *dict) {
19 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
20 // debug(D_DICTIONARY, "Dictionary ATOMIC lock");
21 pthread_mutex_lock(&dict->atomic_mutex);
25 static inline void dictionary_atomic_updates_unlock(DICTIONARY *dict) {
26 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
27 // debug(D_DICTIONARY, "Dictionary ATOMIC unlock");
28 pthread_mutex_unlock(&dict->atomic_mutex);
32 static inline void dictionary_read_lock(DICTIONARY *dict) {
33 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
34 // debug(D_DICTIONARY, "Dictionary READ lock");
35 pthread_rwlock_rdlock(&dict->rwlock);
39 static inline void dictionary_write_lock(DICTIONARY *dict) {
40 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
41 // debug(D_DICTIONARY, "Dictionary WRITE lock");
42 pthread_rwlock_wrlock(&dict->rwlock);
46 static inline void dictionary_unlock(DICTIONARY *dict) {
47 if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
48 // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
49 pthread_rwlock_unlock(&dict->rwlock);
54 // ----------------------------------------------------------------------------
57 static int name_value_iterator(avl *a) { if(a) {}; return 0; }
59 static int name_value_compare(void* a, void* b) {
60 if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
61 else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
62 else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
65 #define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
66 #define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
68 static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
69 NAME_VALUE *result = NULL, tmp;
70 tmp.hash = (hash)?hash:simple_hash(name);
71 tmp.name = (char *)name;
74 avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
79 // ----------------------------------------------------------------------------
82 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
83 debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
85 NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
86 if(unlikely(!nv)) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
88 if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
89 nv->name = (char *)name;
91 nv->name = strdup(name);
92 if (unlikely(!nv->name))
93 fatal("Cannot allocate name_value.name of size %z", strlen(name));
96 nv->hash = (hash)?hash:simple_hash(nv->name);
98 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
101 nv->value = malloc(value_len);
102 if (unlikely(!nv->value))
103 fatal("Cannot allocate name_value.value of size %z", value_len);
105 memcpy(nv->value, value, value_len);
109 dictionary_name_value_index_add_nolock(dict, nv);
115 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
116 debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
118 dictionary_name_value_index_del_nolock(dict, nv);
122 if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
123 debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
127 if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
128 debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
135 // ----------------------------------------------------------------------------
136 // API - basic methods
138 DICTIONARY *dictionary_create(uint32_t flags) {
139 debug(D_DICTIONARY, "Creating dictionary.");
141 DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
142 if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY");
144 avl_init(&dict->values_index, name_value_compare);
145 pthread_rwlock_init(&dict->rwlock, NULL);
146 pthread_mutex_init(&dict->atomic_mutex, NULL);
153 void dictionary_destroy(DICTIONARY *dict) {
154 debug(D_DICTIONARY, "Destroying dictionary.");
156 dictionary_atomic_updates_lock(dict);
158 dictionary_write_lock(dict);
160 while(dict->values_index.root)
161 dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
163 dictionary_unlock(dict);
165 dictionary_atomic_updates_unlock(dict);
170 // ----------------------------------------------------------------------------
172 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
173 debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
175 uint32_t hash = simple_hash(name);
177 dictionary_atomic_updates_lock(dict);
179 dictionary_read_lock(dict);
180 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
181 dictionary_unlock(dict);
184 debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
186 dictionary_write_lock(dict);
187 nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
188 dictionary_unlock(dict);
191 fatal("Cannot create name_value.");
194 debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
196 if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
197 debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
201 debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
203 void *value = malloc(value_len),
206 if(unlikely(!nv->value))
207 fatal("Cannot allocate value of size %z", value_len);
209 memcpy(value, value, value_len);
212 debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
217 dictionary_atomic_updates_unlock(dict);
222 void *dictionary_get(DICTIONARY *dict, const char *name) {
223 debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
225 dictionary_read_lock(dict);
226 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
227 dictionary_unlock(dict);
230 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
234 debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
238 int dictionary_del(DICTIONARY *dict, const char *name) {
241 debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
243 dictionary_atomic_updates_lock(dict);
245 dictionary_read_lock(dict);
246 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
247 dictionary_unlock(dict);
250 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
254 debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
255 dictionary_write_lock(dict);
256 dictionary_name_value_destroy_nolock(dict, nv);
257 dictionary_unlock(dict);
261 dictionary_atomic_updates_unlock(dict);
267 // ----------------------------------------------------------------------------
268 // API - walk through the dictionary
269 // the dictionary is locked for reading while this happens
270 // do not user other dictionary calls while walking the dictionary - deadlock!
272 static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
273 int total = 0, ret = 0;
276 ret = dictionary_walker(a->right, callback, data);
277 if(ret < 0) return ret;
281 ret = callback(((NAME_VALUE *)a)->value, data);
282 if(ret < 0) return ret;
286 dictionary_walker(a->left, callback, data);
287 if (ret < 0) return ret;
294 int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) {
297 dictionary_read_lock(dict);
299 if(likely(dict->values_index.root))
300 ret = dictionary_walker(dict->values_index.root, callback, data);
302 dictionary_unlock(dict);