X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fdaemon%2Futils_cache.c;h=0929872537a61e7a51fccb4804e775b32646b57d;hb=6d8031d73b7c1d874d7afa4cad2f248c4073764d;hp=45444c7f912b4575984ca1937240beb3ce04ba12;hpb=ae5cca244ff291c17df1cc36e28f19376958a2eb;p=collectd.git diff --git a/src/daemon/utils_cache.c b/src/daemon/utils_cache.c index 45444c7f..09298725 100644 --- a/src/daemon/utils_cache.c +++ b/src/daemon/utils_cache.c @@ -1,6 +1,7 @@ /** * collectd - src/utils_cache.c * Copyright (C) 2007-2010 Florian octo Forster + * Copyright (C) 2016 Sebastian tokkee Harl * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,9 +23,11 @@ * * Authors: * Florian octo Forster + * Sebastian tokkee Harl **/ #include "collectd.h" + #include "common.h" #include "plugin.h" #include "utils_avltree.h" @@ -32,12 +35,11 @@ #include "meta_data.h" #include -#include typedef struct cache_entry_s { char name[6 * DATA_MAX_NAME_LEN]; - int values_num; + size_t values_num; gauge_t *values_gauge; value_t *values_raw; /* Time contained in the package @@ -47,7 +49,7 @@ typedef struct cache_entry_s * (for purging old entries) */ cdtime_t last_update; /* Interval in which the data is collected - * (for purding old entries) */ + * (for purging old entries) */ cdtime_t interval; int state; int hits; @@ -68,6 +70,13 @@ typedef struct cache_entry_s meta_data_t *meta; } cache_entry_t; +struct uc_iter_s { + c_avl_iterator_t *iter; + + char *name; + cache_entry_t *entry; +}; + static c_avl_tree_t *cache_tree = NULL; static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; @@ -79,17 +88,16 @@ static int cache_compare (const cache_entry_t *a, const cache_entry_t *b) return (strcmp (a->name, b->name)); } /* int cache_compare */ -static cache_entry_t *cache_alloc (int values_num) +static cache_entry_t *cache_alloc (size_t values_num) { cache_entry_t *ce; - ce = (cache_entry_t *) malloc (sizeof (cache_entry_t)); + ce = calloc (1, sizeof (*ce)); if (ce == NULL) { - ERROR ("utils_cache: cache_alloc: malloc failed."); + ERROR ("utils_cache: cache_alloc: calloc failed."); return (NULL); } - memset (ce, '\0', sizeof (cache_entry_t)); ce->values_num = values_num; ce->values_gauge = calloc (values_num, sizeof (*ce->values_gauge)); @@ -128,9 +136,7 @@ static void cache_free (cache_entry_t *ce) static void uc_check_range (const data_set_t *ds, cache_entry_t *ce) { - int i; - - for (i = 0; i < ds->ds_num; i++) + for (size_t i = 0; i < ds->ds_num; i++) { if (isnan (ce->values_gauge[i])) continue; @@ -144,7 +150,6 @@ static void uc_check_range (const data_set_t *ds, cache_entry_t *ce) static int uc_insert (const data_set_t *ds, const value_list_t *vl, const char *key) { - int i; char *key_copy; cache_entry_t *ce; @@ -161,13 +166,13 @@ static int uc_insert (const data_set_t *ds, const value_list_t *vl, if (ce == NULL) { sfree (key_copy); - ERROR ("uc_insert: cache_alloc (%i) failed.", ds->ds_num); + ERROR ("uc_insert: cache_alloc (%zu) failed.", ds->ds_num); return (-1); } sstrncpy (ce->name, key, sizeof (ce->name)); - for (i = 0; i < ds->ds_num; i++) + for (size_t i = 0; i < ds->ds_num; i++) { switch (ds->ds[i].type) { @@ -234,82 +239,54 @@ int uc_init (void) int uc_check_timeout (void) { - cdtime_t now; - cache_entry_t *ce; - - char **keys = NULL; - cdtime_t *keys_time = NULL; - cdtime_t *keys_interval = NULL; - int keys_len = 0; + cdtime_t now = cdtime(); - char *key; - c_avl_iterator_t *iter; + struct { + char *key; + cdtime_t time; + cdtime_t interval; + } *expired = NULL; + size_t expired_num = 0; - int status; - int i; - pthread_mutex_lock (&cache_lock); - now = cdtime (); - /* Build a list of entries to be flushed */ - iter = c_avl_get_iterator (cache_tree); + c_avl_iterator_t *iter = c_avl_get_iterator (cache_tree); + char *key = NULL; + cache_entry_t *ce = NULL; while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0) { - char **tmp; - cdtime_t *tmp_time; - /* If the entry is fresh enough, continue. */ if ((now - ce->last_update) < (ce->interval * timeout_g)) continue; - /* If entry has not been updated, add to `keys' array */ - tmp = (char **) realloc ((void *) keys, - (keys_len + 1) * sizeof (char *)); + void *tmp = realloc (expired, (expired_num + 1) * sizeof (*expired)); if (tmp == NULL) { ERROR ("uc_check_timeout: realloc failed."); continue; } - keys = tmp; + expired = tmp; - tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time)); - if (tmp_time == NULL) - { - ERROR ("uc_check_timeout: realloc failed."); - continue; - } - keys_time = tmp_time; + expired[expired_num].key = strdup (key); + expired[expired_num].time = ce->last_time; + expired[expired_num].interval = ce->interval; - tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval)); - if (tmp_time == NULL) - { - ERROR ("uc_check_timeout: realloc failed."); - continue; - } - keys_interval = tmp_time; - - keys[keys_len] = strdup (key); - if (keys[keys_len] == NULL) + if (expired[expired_num].key == NULL) { ERROR ("uc_check_timeout: strdup failed."); continue; } - keys_time[keys_len] = ce->last_time; - keys_interval[keys_len] = ce->interval; - keys_len++; + expired_num++; } /* while (c_avl_iterator_next) */ c_avl_iterator_destroy (iter); pthread_mutex_unlock (&cache_lock); - if (keys_len == 0) + if (expired_num == 0) { - /* realloc() may have been called for these. */ - sfree (keys); - sfree (keys_time); - sfree (keys_interval); + sfree (expired); return (0); } @@ -318,55 +295,45 @@ int uc_check_timeout (void) * including plugin specific meta data, rates, history, …. This must be done * without holding the lock, otherwise we will run into a deadlock if a * plugin calls the cache interface. */ - for (i = 0; i < keys_len; i++) + for (size_t i = 0; i < expired_num; i++) { - value_list_t vl = VALUE_LIST_INIT; - - vl.values = NULL; - vl.values_len = 0; - vl.meta = NULL; + value_list_t vl = { + .time = expired[i].time, + .interval = expired[i].interval, + }; - status = parse_identifier_vl (keys[i], &vl); - if (status != 0) + if (parse_identifier_vl (expired[i].key, &vl) != 0) { - ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]); + ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", expired[i].key); continue; } - vl.time = keys_time[i]; - vl.interval = keys_interval[i]; - plugin_dispatch_missing (&vl); - } /* for (i = 0; i < keys_len; i++) */ + } /* for (i = 0; i < expired_num; i++) */ /* Now actually remove all the values from the cache. We don't re-evaluate * the timestamp again, so in theory it is possible we remove a value after * it is updated here. */ pthread_mutex_lock (&cache_lock); - for (i = 0; i < keys_len; i++) + for (size_t i = 0; i < expired_num; i++) { - key = NULL; - ce = NULL; + char *key = NULL; + cache_entry_t *value = NULL; - status = c_avl_remove (cache_tree, keys[i], - (void *) &key, (void *) &ce); - if (status != 0) + if (c_avl_remove (cache_tree, expired[i].key, (void *) &key, (void *) &value) != 0) { - ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]); - sfree (keys[i]); + ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", expired[i].key); + sfree (expired[i].key); continue; } - - sfree (keys[i]); sfree (key); - cache_free (ce); - } /* for (i = 0; i < keys_len; i++) */ - pthread_mutex_unlock (&cache_lock); + cache_free (value); - sfree (keys); - sfree (keys_time); - sfree (keys_interval); + sfree (expired[i].key); + } /* for (i = 0; i < expired_num; i++) */ + pthread_mutex_unlock (&cache_lock); + sfree (expired); return (0); } /* int uc_check_timeout */ @@ -375,7 +342,6 @@ int uc_update (const data_set_t *ds, const value_list_t *vl) char name[6 * DATA_MAX_NAME_LEN]; cache_entry_t *ce = NULL; int status; - int i; if (FORMAT_VL (name, sizeof (name), vl) != 0) { @@ -407,29 +373,13 @@ int uc_update (const data_set_t *ds, const value_list_t *vl) return (-1); } - for (i = 0; i < ds->ds_num; i++) + for (size_t i = 0; i < ds->ds_num; i++) { switch (ds->ds[i].type) { case DS_TYPE_COUNTER: { - counter_t diff; - - /* check if the counter has wrapped around */ - if (vl->values[i].counter < ce->values_raw[i].counter) - { - if (ce->values_raw[i].counter <= 4294967295U) - diff = (4294967295U - ce->values_raw[i].counter) - + vl->values[i].counter; - else - diff = (18446744073709551615ULL - ce->values_raw[i].counter) - + vl->values[i].counter; - } - else /* counter has NOT wrapped around */ - { - diff = vl->values[i].counter - ce->values_raw[i].counter; - } - + counter_t diff = counter_diff (ce->values_raw[i].counter, vl->values[i].counter); ce->values_gauge[i] = ((double) diff) / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time)); ce->values_raw[i].counter = vl->values[i].counter; @@ -443,9 +393,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl) case DS_TYPE_DERIVE: { - derive_t diff; - - diff = vl->values[i].derive - ce->values_raw[i].derive; + derive_t diff = vl->values[i].derive - ce->values_raw[i].derive; ce->values_gauge[i] = ((double) diff) / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time)); @@ -467,14 +415,14 @@ int uc_update (const data_set_t *ds, const value_list_t *vl) return (-1); } /* switch (ds->ds[i].type) */ - DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]); + DEBUG ("uc_update: %s: ds[%zu] = %lf", name, i, ce->values_gauge[i]); } /* for (i) */ /* Update the history if it exists. */ if (ce->history != NULL) { assert (ce->history_index < ce->history_length); - for (i = 0; i < ce->values_num; i++) + for (size_t i = 0; i < ce->values_num; i++) { size_t hist_idx = (ce->values_num * ce->history_index) + i; ce->history[hist_idx] = ce->values_gauge[i]; @@ -517,7 +465,7 @@ int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_val else { ret_num = ce->values_num; - ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t)); + ret = malloc (ret_num * sizeof (*ret)); if (ret == NULL) { ERROR ("utils_cache: uc_get_rate_by_name: malloc failed."); @@ -567,7 +515,7 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl) * values are returned. */ if (ret_num != (size_t) ds->ds_num) { - ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, " + ERROR ("utils_cache: uc_get_rate: ds[%s] has %zu values, " "but uc_get_rate_by_name returned %zu.", ds->type, ds->ds_num, ret_num); sfree (ret); @@ -654,9 +602,7 @@ int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number) if (status != 0) { - size_t i; - - for (i = 0; i < number; i++) + for (size_t i = 0; i < number; i++) { sfree (names[i]); } @@ -709,7 +655,7 @@ int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state) if (FORMAT_VL (name, sizeof (name), vl) != 0) { - ERROR ("uc_get_state: FORMAT_VL failed."); + ERROR ("uc_set_state: FORMAT_VL failed."); return (STATE_ERROR); } @@ -731,7 +677,6 @@ int uc_get_history_by_name (const char *name, gauge_t *ret_history, size_t num_steps, size_t num_ds) { cache_entry_t *ce = NULL; - size_t i; int status = 0; pthread_mutex_lock (&cache_lock); @@ -763,7 +708,7 @@ int uc_get_history_by_name (const char *name, return (-ENOMEM); } - for (i = ce->history_length * ce->values_num; + for (size_t i = ce->history_length * ce->values_num; i < (num_steps * ce->values_num); i++) tmp[i] = NAN; @@ -773,7 +718,7 @@ int uc_get_history_by_name (const char *name, } /* if (ce->history_length < num_steps) */ /* Copy the values to the output buffer. */ - for (i = 0; i < num_steps; i++) + for (size_t i = 0; i < num_steps; i++) { size_t src_index; size_t dst_index; @@ -817,7 +762,7 @@ int uc_get_hits (const data_set_t *ds, const value_list_t *vl) if (FORMAT_VL (name, sizeof (name), vl) != 0) { - ERROR ("uc_get_state: FORMAT_VL failed."); + ERROR ("uc_get_hits: FORMAT_VL failed."); return (STATE_ERROR); } @@ -842,7 +787,7 @@ int uc_set_hits (const data_set_t *ds, const value_list_t *vl, int hits) if (FORMAT_VL (name, sizeof (name), vl) != 0) { - ERROR ("uc_get_state: FORMAT_VL failed."); + ERROR ("uc_set_hits: FORMAT_VL failed."); return (STATE_ERROR); } @@ -868,7 +813,7 @@ int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step) if (FORMAT_VL (name, sizeof (name), vl) != 0) { - ERROR ("uc_get_state: FORMAT_VL failed."); + ERROR ("uc_inc_hits: FORMAT_VL failed."); return (STATE_ERROR); } @@ -887,6 +832,102 @@ int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step) } /* int uc_inc_hits */ /* + * Iterator interface + */ +uc_iter_t *uc_get_iterator (void) +{ + uc_iter_t *iter; + + iter = (uc_iter_t *) calloc(1, sizeof (*iter)); + if (iter == NULL) + return (NULL); + + pthread_mutex_lock (&cache_lock); + + iter->iter = c_avl_get_iterator (cache_tree); + if (iter->iter == NULL) + { + free (iter); + return (NULL); + } + + return (iter); +} /* uc_iter_t *uc_get_iterator */ + +int uc_iterator_next (uc_iter_t *iter, char **ret_name) +{ + int status; + + if (iter == NULL) + return (-1); + + while ((status = c_avl_iterator_next (iter->iter, + (void *) &iter->name, (void *) &iter->entry)) == 0) + { + if (iter->entry->state == STATE_MISSING) + continue; + + break; + } + if (status != 0) { + iter->name = NULL; + iter->entry = NULL; + return (-1); + } + + if (ret_name != NULL) + *ret_name = iter->name; + + return (0); +} /* int uc_iterator_next */ + +void uc_iterator_destroy (uc_iter_t *iter) +{ + if (iter == NULL) + return; + + c_avl_iterator_destroy (iter->iter); + pthread_mutex_unlock (&cache_lock); + + free (iter); +} /* void uc_iterator_destroy */ + +int uc_iterator_get_time (uc_iter_t *iter, cdtime_t *ret_time) +{ + if ((iter == NULL) || (iter->entry == NULL) || (ret_time == NULL)) + return (-1); + + *ret_time = iter->entry->last_time; + return (0); +} /* int uc_iterator_get_name */ + +int uc_iterator_get_values (uc_iter_t *iter, value_t **ret_values, size_t *ret_num) +{ + if ((iter == NULL) || (iter->entry == NULL) + || (ret_values == NULL) || (ret_num == NULL)) + return (-1); + + *ret_values = calloc (iter->entry->values_num, sizeof(*iter->entry->values_raw)); + if (*ret_values == NULL) + return (-1); + for (size_t i = 0; i < iter->entry->values_num; ++i) + *ret_values[i] = iter->entry->values_raw[i]; + + *ret_num = iter->entry->values_num; + + return (0); +} /* int uc_iterator_get_values */ + +int uc_iterator_get_interval (uc_iter_t *iter, cdtime_t *ret_interval) +{ + if ((iter == NULL) || (iter->entry == NULL) || (ret_interval == NULL)) + return (-1); + + *ret_interval = iter->entry->interval; + return (0); +} /* int uc_iterator_get_name */ + +/* * Meta data interface */ /* XXX: This function will acquire `cache_lock' but will not free it! */