@cryptotaxi247 / netdata-1 / commits / c9035e21e

atomic locks on dictionary_set(), dictionary_del(), dictionary_destroy()

Costa Tsaousis (ktsaou) committed May 9, 2016 at 16:35 UTC c9035e21e75c72c6db44617086da6dd288a40f7b
2 files changed +71 -28
src/dictionary.c
+70 -28
@@ -13,52 +13,71 @@
13 #include "dictionary.h"
14
15 // ----------------------------------------------------------------------------
16 -// name_value index
16 +// dictionary locks
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);
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);
22 + }
23 }
24
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 -
37 - return result;
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);
29 + }
30 }
31
40 -static void dictionary_read_lock(DICTIONARY *dict) {
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);
36 }
37 }
38
47 -static void dictionary_write_lock(DICTIONARY *dict) {
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);
43 }
44 }
45
54 -static void dictionary_unlock(DICTIONARY *dict) {
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);
50 }
51 }
52
53 +
54 // ----------------------------------------------------------------------------
55 +// avl index
56 +
57 +static int name_value_iterator(avl *a) { if(a) {}; return 0; }
58 +
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);
63 +}
64 +
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)
67 +
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;
72 +
73 + dict->searches++;
74 + avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
75 +
76 + return result;
77 +}
78 +
79 +// ----------------------------------------------------------------------------
80 +// internal methods
81
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);
@@ -114,6 +133,7 @@ static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *n
133 }
134
135 // ----------------------------------------------------------------------------
136 +// API - basic methods
137
138 DICTIONARY *dictionary_create(uint32_t flags) {
139 debug(D_DICTIONARY, "Creating dictionary.");
@@ -123,6 +143,7 @@ DICTIONARY *dictionary_create(uint32_t flags) {
143
144 avl_init(&dict->values_index, name_value_compare);
145 pthread_rwlock_init(&dict->rwlock, NULL);
146 + pthread_mutex_init(&dict->atomic_mutex, NULL);
147
148 dict->flags = flags;
149
@@ -132,6 +153,8 @@ DICTIONARY *dictionary_create(uint32_t flags) {
153 void dictionary_destroy(DICTIONARY *dict) {
154 debug(D_DICTIONARY, "Destroying dictionary.");
155
156 + dictionary_atomic_updates_lock(dict);
157 +
158 dictionary_write_lock(dict);
159
160 while(dict->values_index.root)
@@ -139,6 +162,8 @@ void dictionary_destroy(DICTIONARY *dict) {
162
163 dictionary_unlock(dict);
164
165 + dictionary_atomic_updates_unlock(dict);
166 +
167 free(dict);
168 }
169
@@ -149,6 +174,8 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
174
175 uint32_t hash = simple_hash(name);
176
177 + dictionary_atomic_updates_lock(dict);
178 +
179 dictionary_read_lock(dict);
180 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
181 dictionary_unlock(dict);
@@ -187,6 +214,8 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
214 }
215 }
216
217 + dictionary_atomic_updates_unlock(dict);
218 +
219 return nv->value;
220 }
221
@@ -207,26 +236,39 @@ void *dictionary_get(DICTIONARY *dict, const char *name) {
236 }
237
238 int dictionary_del(DICTIONARY *dict, const char *name) {
239 + int ret;
240 +
241 debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
242
243 + dictionary_atomic_updates_lock(dict);
244 +
245 dictionary_read_lock(dict);
246 NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
247 dictionary_unlock(dict);
248
249 if(unlikely(!nv)) {
250 debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
218 - return -1;
251 + ret = -1;
252 + }
253 + else {
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);
258 + ret = 0;
259 }
260
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);
261 + dictionary_atomic_updates_unlock(dict);
262
226 - return 0;
263 + return ret;
264 }
265
266
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!
271 +
272 static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
273 int total = 0, ret = 0;
274
src/dictionary.h
+1
@@ -26,6 +26,7 @@ typedef struct dictionary {
26
27 avl_tree values_index;
28 pthread_rwlock_t rwlock;
29 + pthread_mutex_t atomic_mutex;
30 } DICTIONARY;
31
32 #define DICTIONARY_FLAG_DEFAULT 0x00000000