]> arthur.barton.de Git - netdata.git/commitdiff
atomic locks on dictionary_set(), dictionary_del(), dictionary_destroy()
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Mon, 9 May 2016 13:35:21 +0000 (16:35 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Mon, 9 May 2016 13:35:21 +0000 (16:35 +0300)
src/dictionary.c
src/dictionary.h

index b7c904cec6fe11344f5a67444c2259acc0b12a9b..1f9a26aeacf18bec52f42dee2c9c4bb18d484e5c 100644 (file)
 #include "dictionary.h"
 
 // ----------------------------------------------------------------------------
-// name_value index
+// dictionary locks
 
-static int name_value_iterator(avl *a) { if(a) {}; return 0; }
-
-static int name_value_compare(void* a, void* b) {
-       if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
-       else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
-       else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
+static inline void dictionary_atomic_updates_lock(DICTIONARY *dict) {
+       if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
+               // debug(D_DICTIONARY, "Dictionary ATOMIC lock");
+               pthread_mutex_lock(&dict->atomic_mutex);
+       }
 }
 
-#define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
-#define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
-
-static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
-       NAME_VALUE *result = NULL, tmp;
-       tmp.hash = (hash)?hash:simple_hash(name);
-       tmp.name = (char *)name;
-
-       dict->searches++;
-       avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
-
-       return result;
+static inline void dictionary_atomic_updates_unlock(DICTIONARY *dict) {
+       if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
+               // debug(D_DICTIONARY, "Dictionary ATOMIC unlock");
+               pthread_mutex_unlock(&dict->atomic_mutex);
+       }
 }
 
-static void dictionary_read_lock(DICTIONARY *dict) {
+static inline void dictionary_read_lock(DICTIONARY *dict) {
        if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
                // debug(D_DICTIONARY, "Dictionary READ lock");
                pthread_rwlock_rdlock(&dict->rwlock);
        }
 }
 
-static void dictionary_write_lock(DICTIONARY *dict) {
+static inline void dictionary_write_lock(DICTIONARY *dict) {
        if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
                // debug(D_DICTIONARY, "Dictionary WRITE lock");
                pthread_rwlock_wrlock(&dict->rwlock);
        }
 }
 
-static void dictionary_unlock(DICTIONARY *dict) {
+static inline void dictionary_unlock(DICTIONARY *dict) {
        if(likely(!(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))) {
                // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
                pthread_rwlock_unlock(&dict->rwlock);
        }
 }
 
+
 // ----------------------------------------------------------------------------
+// avl index
+
+static int name_value_iterator(avl *a) { if(a) {}; return 0; }
+
+static int name_value_compare(void* a, void* b) {
+       if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
+       else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
+       else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
+}
+
+#define dictionary_name_value_index_add_nolock(dict, nv) do { (dict)->inserts++; avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
+#define dictionary_name_value_index_del_nolock(dict, nv) do { (dict)->deletes++; avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
+
+static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
+       NAME_VALUE *result = NULL, tmp;
+       tmp.hash = (hash)?hash:simple_hash(name);
+       tmp.name = (char *)name;
+
+       dict->searches++;
+       avl_search(&(dict->values_index), (avl *)&tmp, name_value_iterator, (avl **)&result);
+
+       return result;
+}
+
+// ----------------------------------------------------------------------------
+// internal methods
 
 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
        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
 }
 
 // ----------------------------------------------------------------------------
+// API - basic methods
 
 DICTIONARY *dictionary_create(uint32_t flags) {
        debug(D_DICTIONARY, "Creating dictionary.");
@@ -123,6 +143,7 @@ DICTIONARY *dictionary_create(uint32_t flags) {
 
        avl_init(&dict->values_index, name_value_compare);
        pthread_rwlock_init(&dict->rwlock, NULL);
+       pthread_mutex_init(&dict->atomic_mutex, NULL);
 
        dict->flags = flags;
 
@@ -132,6 +153,8 @@ DICTIONARY *dictionary_create(uint32_t flags) {
 void dictionary_destroy(DICTIONARY *dict) {
        debug(D_DICTIONARY, "Destroying dictionary.");
 
+       dictionary_atomic_updates_lock(dict);
+
        dictionary_write_lock(dict);
 
        while(dict->values_index.root)
@@ -139,6 +162,8 @@ void dictionary_destroy(DICTIONARY *dict) {
 
        dictionary_unlock(dict);
 
+       dictionary_atomic_updates_unlock(dict);
+
        free(dict);
 }
 
@@ -149,6 +174,8 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
 
        uint32_t hash = simple_hash(name);
 
+       dictionary_atomic_updates_lock(dict);
+
        dictionary_read_lock(dict);
        NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
        dictionary_unlock(dict);
@@ -187,6 +214,8 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
                }
        }
 
+       dictionary_atomic_updates_unlock(dict);
+
        return nv->value;
 }
 
@@ -207,26 +236,39 @@ void *dictionary_get(DICTIONARY *dict, const char *name) {
 }
 
 int dictionary_del(DICTIONARY *dict, const char *name) {
+       int ret;
+
        debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
 
+       dictionary_atomic_updates_lock(dict);
+
        dictionary_read_lock(dict);
        NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
        dictionary_unlock(dict);
 
        if(unlikely(!nv)) {
                debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
-               return -1;
+               ret = -1;
+       }
+       else {
+               debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
+               dictionary_write_lock(dict);
+               dictionary_name_value_destroy_nolock(dict, nv);
+               dictionary_unlock(dict);
+               ret = 0;
        }
 
-       debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
-       dictionary_write_lock(dict);
-       dictionary_name_value_destroy_nolock(dict, nv);
-       dictionary_unlock(dict);
+       dictionary_atomic_updates_unlock(dict);
 
-       return 0;
+       return ret;
 }
 
 
+// ----------------------------------------------------------------------------
+// API - walk through the dictionary
+// the dictionary is locked for reading while this happens
+// do not user other dictionary calls while walking the dictionary - deadlock!
+
 static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
        int total = 0, ret = 0;
 
index c659d580143bf35b69cc22b7a433c1dbb6b3dd77..e1320da3d5a172c4c561f1b4ecbd08691577e3fc 100644 (file)
@@ -26,6 +26,7 @@ typedef struct dictionary {
 
        avl_tree values_index;
        pthread_rwlock_t rwlock;
+       pthread_mutex_t atomic_mutex;
 } DICTIONARY;
 
 #define DICTIONARY_FLAG_DEFAULT                                        0x00000000