X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=src%2Fdictionary.c;h=512b4bbe6c182bf92d3161c488d3e1b89c5b9d28;hb=909e26f825bc1f6f907231761412c885331fec7e;hp=8dbbc64c4febacc1060dd3095d1e5eec1b7f45b0;hpb=167aa7a2cf5fc455cbbc0cab3dba80c251507c8e;p=netdata.git diff --git a/src/dictionary.c b/src/dictionary.c index 8dbbc64c..512b4bbe 100644 --- a/src/dictionary.c +++ b/src/dictionary.c @@ -1,39 +1,27 @@ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "avl.h" #include "common.h" -#include "log.h" - -#include "dictionary.h" // ---------------------------------------------------------------------------- // dictionary statistics static inline void NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->inserts++; + if(likely(dict->stats)) + dict->stats->inserts++; } static inline void NETDATA_DICTIONARY_STATS_DELETES_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->deletes++; + if(likely(dict->stats)) + dict->stats->deletes++; } static inline void NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->searches++; + if(likely(dict->stats)) + dict->stats->searches++; } static inline void NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->entries++; + if(likely(dict->stats)) + dict->stats->entries++; } static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) { - if(likely(dict->stats)) - dict->stats->entries--; + if(likely(dict->stats)) + dict->stats->entries--; } @@ -41,24 +29,24 @@ static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) { // dictionary locks static inline void dictionary_read_lock(DICTIONARY *dict) { - if(likely(dict->rwlock)) { - // debug(D_DICTIONARY, "Dictionary READ lock"); - pthread_rwlock_rdlock(dict->rwlock); - } + if(likely(dict->rwlock)) { + // debug(D_DICTIONARY, "Dictionary READ lock"); + netdata_rwlock_rdlock(dict->rwlock); + } } static inline void dictionary_write_lock(DICTIONARY *dict) { - if(likely(dict->rwlock)) { - // debug(D_DICTIONARY, "Dictionary WRITE lock"); - pthread_rwlock_wrlock(dict->rwlock); - } + if(likely(dict->rwlock)) { + // debug(D_DICTIONARY, "Dictionary WRITE lock"); + netdata_rwlock_wrlock(dict->rwlock); + } } static inline void dictionary_unlock(DICTIONARY *dict) { - if(likely(dict->rwlock)) { - // debug(D_DICTIONARY, "Dictionary UNLOCK lock"); - pthread_rwlock_unlock(dict->rwlock); - } + if(likely(dict->rwlock)) { + // debug(D_DICTIONARY, "Dictionary UNLOCK lock"); + netdata_rwlock_unlock(dict->rwlock); + } } @@ -66,207 +54,200 @@ static inline void dictionary_unlock(DICTIONARY *dict) { // avl index 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); + 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 { NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict); avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0) -#define dictionary_name_value_index_del_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict); 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 tmp; - tmp.hash = (hash)?hash:simple_hash(name); - tmp.name = (char *)name; + NAME_VALUE tmp; + tmp.hash = (hash)?hash:simple_hash(name); + tmp.name = (char *)name; - NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict); - return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp); + NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict); + return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp); } // ---------------------------------------------------------------------------- // 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); + debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name); - NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE)); - if(unlikely(!nv)) fatal("Cannot allocate name_value of size %zu", sizeof(NAME_VALUE)); + NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE)); - if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE) - nv->name = (char *)name; - else { - nv->name = strdup(name); - if (unlikely(!nv->name)) - fatal("Cannot allocate name_value.name of size %zu", strlen(name)); - } + if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE) + nv->name = (char *)name; + else { + nv->name = strdupz(name); + } - nv->hash = (hash)?hash:simple_hash(nv->name); + nv->hash = (hash)?hash:simple_hash(nv->name); - if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) - nv->value = value; - else { - nv->value = malloc(value_len); - if (unlikely(!nv->value)) - fatal("Cannot allocate name_value.value of size %zu", value_len); + if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) + nv->value = value; + else { + nv->value = mallocz(value_len); + memcpy(nv->value, value, value_len); + } - memcpy(nv->value, value, value_len); - } + // index it + NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict); + if(unlikely(avl_insert(&((dict)->values_index), (avl *)(nv)) != (avl *)nv)) + error("dictionary: INTERNAL ERROR: duplicate insertion to dictionary."); - // index it - dictionary_name_value_index_add_nolock(dict, nv); - NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict); + NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict); - return nv; + return nv; } static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) { - debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name); + debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name); - dictionary_name_value_index_del_nolock(dict, nv); + NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict); + if(unlikely(avl_remove(&(dict->values_index), (avl *)(nv)) != (avl *)nv)) + error("dictionary: INTERNAL ERROR: dictionary invalid removal of node."); - NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict); + NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict); - if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) { - debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name); - free(nv->value); - } + if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) { + debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name); + freez(nv->value); + } - if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) { - debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name); - free(nv->name); - } + if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) { + debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name); + freez(nv->name); + } - free(nv); + freez(nv); } // ---------------------------------------------------------------------------- // API - basic methods -DICTIONARY *dictionary_create(uint32_t flags) { - debug(D_DICTIONARY, "Creating dictionary."); +DICTIONARY *dictionary_create(uint8_t flags) { + debug(D_DICTIONARY, "Creating dictionary."); - DICTIONARY *dict = calloc(1, sizeof(DICTIONARY)); - if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY"); + DICTIONARY *dict = callocz(1, sizeof(DICTIONARY)); - if(flags & DICTIONARY_FLAG_WITH_STATISTICS) { - dict->stats = calloc(1, sizeof(struct dictionary_stats)); - if(!dict->stats) fatal("Cannot allocate statistics for DICTIONARY"); - } + if(flags & DICTIONARY_FLAG_WITH_STATISTICS) + dict->stats = callocz(1, sizeof(struct dictionary_stats)); - if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) { - dict->rwlock = calloc(1, sizeof(pthread_rwlock_t)); - if(!dict->rwlock) fatal("Cannot allocate pthread_rwlock_t for DICTIONARY"); - pthread_rwlock_init(dict->rwlock, NULL); - } + if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) { + dict->rwlock = callocz(1, sizeof(netdata_rwlock_t)); + netdata_rwlock_init(dict->rwlock); + } - avl_init(&dict->values_index, name_value_compare); - dict->flags = flags; + avl_init(&dict->values_index, name_value_compare); + dict->flags = flags; - return dict; + return dict; } void dictionary_destroy(DICTIONARY *dict) { - debug(D_DICTIONARY, "Destroying dictionary."); + debug(D_DICTIONARY, "Destroying dictionary."); - dictionary_write_lock(dict); + dictionary_write_lock(dict); - while(dict->values_index.root) - dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root); + while(dict->values_index.root) + dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root); - dictionary_unlock(dict); + dictionary_unlock(dict); - if(dict->stats) - free(dict->stats); + if(dict->stats) + freez(dict->stats); - if(dict->rwlock) - free(dict->rwlock); + if(dict->rwlock) { + netdata_rwlock_destroy(dict->rwlock); + freez(dict->rwlock); + } - free(dict); + freez(dict); } // ---------------------------------------------------------------------------- void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) { - debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name); - - uint32_t hash = simple_hash(name); + debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name); - dictionary_write_lock(dict); + uint32_t hash = simple_hash(name); - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash); - if(unlikely(!nv)) { - debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name); + dictionary_write_lock(dict); - nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash); - if(unlikely(!nv)) - fatal("Cannot create name_value."); - } - else { - debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name); + NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash); + if(unlikely(!nv)) { + debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name); - if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) { - debug(D_REGISTRY, "Dictionary: linking value to '%s'", name); - nv->value = value; - } - else { - debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name); + nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash); + if(unlikely(!nv)) + fatal("Cannot create name_value."); + } + else { + debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name); - void *value = malloc(value_len), - *old = nv->value; + if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) { + debug(D_REGISTRY, "Dictionary: linking value to '%s'", name); + nv->value = value; + } + else { + debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name); - if(unlikely(!nv->value)) - fatal("Cannot allocate value of size %zu", value_len); + // copy the new value without breaking + // any other thread accessing the same entry + void *new = mallocz(value_len), + *old = nv->value; - memcpy(value, value, value_len); - nv->value = value; + memcpy(new, value, value_len); + nv->value = new; - debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name); - free(old); - } - } + debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name); + freez(old); + } + } - dictionary_unlock(dict); + dictionary_unlock(dict); - return nv->value; + return nv->value; } void *dictionary_get(DICTIONARY *dict, const char *name) { - debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name); + debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name); - dictionary_read_lock(dict); - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0); - dictionary_unlock(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 NULL; - } + if(unlikely(!nv)) { + debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name); + return NULL; + } - debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name); - return nv->value; + debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name); + return nv->value; } int dictionary_del(DICTIONARY *dict, const char *name) { - int ret; + int ret; - debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name); + debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name); - dictionary_write_lock(dict); + dictionary_write_lock(dict); - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0); - if(unlikely(!nv)) { - debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name); - ret = -1; - } - else { - debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name); - dictionary_name_value_destroy_nolock(dict, nv); - ret = 0; - } + NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0); + if(unlikely(!nv)) { + debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name); + ret = -1; + } + else { + debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name); + dictionary_name_value_destroy_nolock(dict, nv); + ret = 0; + } - dictionary_unlock(dict); + dictionary_unlock(dict); - return ret; + return ret; } @@ -276,36 +257,36 @@ int dictionary_del(DICTIONARY *dict, const char *name) { // 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; + int total = 0, ret = 0; - if(a->right) { - ret = dictionary_walker(a->right, callback, data); - if(ret < 0) return ret; - total += ret; - } + if(a->avl_link[0]) { + ret = dictionary_walker(a->avl_link[0], callback, data); + if(ret < 0) return ret; + total += ret; + } - ret = callback(((NAME_VALUE *)a)->value, data); - if(ret < 0) return ret; - total += ret; + ret = callback(((NAME_VALUE *)a)->value, data); + if(ret < 0) return ret; + total += ret; - if(a->left) { - dictionary_walker(a->left, callback, data); - if (ret < 0) return ret; - total += ret; - } + if(a->avl_link[1]) { + ret = dictionary_walker(a->avl_link[1], callback, data); + if (ret < 0) return ret; + total += ret; + } - return total; + return total; } int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) { - int ret = 0; + int ret = 0; - dictionary_read_lock(dict); + dictionary_read_lock(dict); - if(likely(dict->values_index.root)) - ret = dictionary_walker(dict->values_index.root, callback, data); + if(likely(dict->values_index.root)) + ret = dictionary_walker(dict->values_index.root, callback, data); - dictionary_unlock(dict); + dictionary_unlock(dict); - return ret; + return ret; }