X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Frrdtool.c;h=cd275dadc622bd92c18943edecf7da245e10d247;hp=f5e01c81fe522d4fba76842156540594a24d3ef3;hb=ba1015262cdc912f9d01ab5a76037e65033c54c5;hpb=19a7c076959e16df16be966d4c3aa563431ef038 diff --git a/src/rrdtool.c b/src/rrdtool.c index f5e01c81..cd275dad 100644 --- a/src/rrdtool.c +++ b/src/rrdtool.c @@ -25,8 +25,8 @@ #include "collectd.h" -#include "plugin.h" #include "common.h" +#include "plugin.h" #include "utils_avltree.h" #include "utils_random.h" #include "utils_rrdcreate.h" @@ -36,93 +36,69 @@ /* * Private types */ -struct rrd_cache_s -{ - int values_num; - char **values; - cdtime_t first_value; - cdtime_t last_value; - int64_t random_variation; - enum - { - FLAG_NONE = 0x00, - FLAG_QUEUED = 0x01, - FLAG_FLUSHQ = 0x02 - } flags; -}; -typedef struct rrd_cache_s rrd_cache_t; - -enum rrd_queue_dir_e -{ - QUEUE_INSERT_FRONT, - QUEUE_INSERT_BACK -}; +typedef struct rrd_cache_s { + int values_num; + char **values; + cdtime_t first_value; + cdtime_t last_value; + int64_t random_variation; + enum { FLAG_NONE = 0x00, FLAG_QUEUED = 0x01, FLAG_FLUSHQ = 0x02 } flags; +} rrd_cache_t; + +enum rrd_queue_dir_e { QUEUE_INSERT_FRONT, QUEUE_INSERT_BACK }; typedef enum rrd_queue_dir_e rrd_queue_dir_t; -struct rrd_queue_s -{ - char *filename; - struct rrd_queue_s *next; +struct rrd_queue_s { + char *filename; + struct rrd_queue_s *next; }; typedef struct rrd_queue_s rrd_queue_t; /* * Private variables */ -static const char *config_keys[] = -{ - "CacheTimeout", - "CacheFlush", - "CreateFilesAsync", - "DataDir", - "StepSize", - "HeartBeat", - "RRARows", - "RRATimespan", - "XFF", - "WritesPerSecond", - "RandomTimeout" -}; -static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); +static const char *config_keys[] = { + "CacheTimeout", "CacheFlush", "CreateFilesAsync", "DataDir", + "StepSize", "HeartBeat", "RRARows", "RRATimespan", + "XFF", "WritesPerSecond", "RandomTimeout"}; +static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); /* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat * is zero a default, depending on the `interval' member of the value list is * being used. */ -static char *datadir = NULL; +static char *datadir = NULL; static double write_rate = 0.0; -static rrdcreate_config_t rrdcreate_config = -{ - /* stepsize = */ 0, - /* heartbeat = */ 0, - /* rrarows = */ 1200, - /* xff = */ 0.1, +static rrdcreate_config_t rrdcreate_config = { + /* stepsize = */ 0, + /* heartbeat = */ 0, + /* rrarows = */ 1200, + /* xff = */ 0.1, - /* timespans = */ NULL, - /* timespans_num = */ 0, + /* timespans = */ NULL, + /* timespans_num = */ 0, - /* consolidation_functions = */ NULL, - /* consolidation_functions_num = */ 0, + /* consolidation_functions = */ NULL, + /* consolidation_functions_num = */ 0, - /* async = */ 0 -}; + /* async = */ 0}; /* XXX: If you need to lock both, cache_lock and queue_lock, at the same time, * ALWAYS lock `cache_lock' first! */ -static cdtime_t cache_timeout = 0; -static cdtime_t cache_flush_timeout = 0; -static cdtime_t random_timeout = TIME_T_TO_CDTIME_T_STATIC (1); -static cdtime_t cache_flush_last; +static cdtime_t cache_timeout = 0; +static cdtime_t cache_flush_timeout = 0; +static cdtime_t random_timeout = 0; +static cdtime_t cache_flush_last; static c_avl_tree_t *cache = NULL; static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; -static rrd_queue_t *queue_head = NULL; -static rrd_queue_t *queue_tail = NULL; -static rrd_queue_t *flushq_head = NULL; -static rrd_queue_t *flushq_tail = NULL; -static pthread_t queue_thread; -static int queue_thread_running = 1; +static rrd_queue_t *queue_head = NULL; +static rrd_queue_t *queue_tail = NULL; +static rrd_queue_t *flushq_head = NULL; +static rrd_queue_t *flushq_tail = NULL; +static pthread_t queue_thread; +static int queue_thread_running = 1; static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; #if !HAVE_THREADSAFE_LIBRRD static pthread_mutex_t librrd_lock = PTHREAD_MUTEX_INITIALIZER; @@ -131,364 +107,333 @@ static pthread_mutex_t librrd_lock = PTHREAD_MUTEX_INITIALIZER; static int do_shutdown = 0; #if HAVE_THREADSAFE_LIBRRD -static int srrd_update (char *filename, char *template, - int argc, const char **argv) -{ - int status; - - optind = 0; /* bug in librrd? */ - rrd_clear_error (); - - status = rrd_update_r (filename, template, argc, (void *) argv); - - if (status != 0) - { - WARNING ("rrdtool plugin: rrd_update_r (%s) failed: %s", - filename, rrd_get_error ()); - } +static int srrd_update(char *filename, char *template, int argc, + const char **argv) { + optind = 0; /* bug in librrd? */ + rrd_clear_error(); + + int status = rrd_update_r(filename, template, argc, (void *)argv); + if (status != 0) { + WARNING("rrdtool plugin: rrd_update_r (%s) failed: %s", filename, + rrd_get_error()); + } - return (status); + return status; } /* int srrd_update */ /* #endif HAVE_THREADSAFE_LIBRRD */ -#else /* !HAVE_THREADSAFE_LIBRRD */ -static int srrd_update (char *filename, char *template, - int argc, const char **argv) -{ - int status; +#else /* !HAVE_THREADSAFE_LIBRRD */ +static int srrd_update(char *filename, char *template, int argc, + const char **argv) { + int status; - int new_argc; - char **new_argv; + int new_argc; + char **new_argv; - assert (template == NULL); + assert(template == NULL); - new_argc = 2 + argc; - new_argv = malloc ((new_argc + 1) * sizeof (*new_argv)); - if (new_argv == NULL) - { - ERROR ("rrdtool plugin: malloc failed."); - return (-1); - } + new_argc = 2 + argc; + new_argv = malloc((new_argc + 1) * sizeof(*new_argv)); + if (new_argv == NULL) { + ERROR("rrdtool plugin: malloc failed."); + return -1; + } - new_argv[0] = "update"; - new_argv[1] = filename; + new_argv[0] = "update"; + new_argv[1] = filename; - memcpy (new_argv + 2, argv, argc * sizeof (char *)); - new_argv[new_argc] = NULL; + memcpy(new_argv + 2, argv, argc * sizeof(char *)); + new_argv[new_argc] = NULL; - pthread_mutex_lock (&librrd_lock); - optind = 0; /* bug in librrd? */ - rrd_clear_error (); + pthread_mutex_lock(&librrd_lock); + optind = 0; /* bug in librrd? */ + rrd_clear_error(); - status = rrd_update (new_argc, new_argv); - pthread_mutex_unlock (&librrd_lock); + status = rrd_update(new_argc, new_argv); + pthread_mutex_unlock(&librrd_lock); - if (status != 0) - { - WARNING ("rrdtool plugin: rrd_update_r failed: %s: %s", - filename, rrd_get_error ()); - } + if (status != 0) { + WARNING("rrdtool plugin: rrd_update_r failed: %s: %s", filename, + rrd_get_error()); + } - sfree (new_argv); + sfree(new_argv); - return (status); + return status; } /* int srrd_update */ #endif /* !HAVE_THREADSAFE_LIBRRD */ -static int value_list_to_string_multiple (char *buffer, int buffer_len, - const data_set_t *ds, const value_list_t *vl) -{ - int offset; - int status; - time_t tt; - - memset (buffer, '\0', buffer_len); - - tt = CDTIME_T_TO_TIME_T (vl->time); - status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) tt); - if ((status < 1) || (status >= buffer_len)) - return (-1); - offset = status; - - for (size_t i = 0; i < ds->ds_num; i++) - { - if ((ds->ds[i].type != DS_TYPE_COUNTER) - && (ds->ds[i].type != DS_TYPE_GAUGE) - && (ds->ds[i].type != DS_TYPE_DERIVE) - && (ds->ds[i].type != DS_TYPE_ABSOLUTE)) - return (-1); - - if (ds->ds[i].type == DS_TYPE_COUNTER) - status = ssnprintf (buffer + offset, buffer_len - offset, - ":%llu", vl->values[i].counter); - else if (ds->ds[i].type == DS_TYPE_GAUGE) - status = ssnprintf (buffer + offset, buffer_len - offset, - ":"GAUGE_FORMAT, vl->values[i].gauge); - else if (ds->ds[i].type == DS_TYPE_DERIVE) - status = ssnprintf (buffer + offset, buffer_len - offset, - ":%"PRIi64, vl->values[i].derive); - else /*if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ - status = ssnprintf (buffer + offset, buffer_len - offset, - ":%"PRIu64, vl->values[i].absolute); - - if ((status < 1) || (status >= (buffer_len - offset))) - return (-1); - - offset += status; - } /* for ds->ds_num */ - - return (0); +static int value_list_to_string_multiple(char *buffer, int buffer_len, + const data_set_t *ds, + const value_list_t *vl) { + int offset; + int status; + time_t tt; + + memset(buffer, '\0', buffer_len); + + tt = CDTIME_T_TO_TIME_T(vl->time); + status = snprintf(buffer, buffer_len, "%u", (unsigned int)tt); + if ((status < 1) || (status >= buffer_len)) + return -1; + offset = status; + + for (size_t i = 0; i < ds->ds_num; i++) { + if ((ds->ds[i].type != DS_TYPE_COUNTER) && + (ds->ds[i].type != DS_TYPE_GAUGE) && + (ds->ds[i].type != DS_TYPE_DERIVE) && + (ds->ds[i].type != DS_TYPE_ABSOLUTE)) + return -1; + + if (ds->ds[i].type == DS_TYPE_COUNTER) + status = snprintf(buffer + offset, buffer_len - offset, ":%llu", + vl->values[i].counter); + else if (ds->ds[i].type == DS_TYPE_GAUGE) + status = snprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT, + vl->values[i].gauge); + else if (ds->ds[i].type == DS_TYPE_DERIVE) + status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIi64, + vl->values[i].derive); + else /*if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ + status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64, + vl->values[i].absolute); + + if ((status < 1) || (status >= (buffer_len - offset))) + return -1; + + offset += status; + } /* for ds->ds_num */ + + return 0; } /* int value_list_to_string_multiple */ -static int value_list_to_string (char *buffer, int buffer_len, - const data_set_t *ds, const value_list_t *vl) -{ - int status; - time_t tt; - - if (ds->ds_num != 1) - return (value_list_to_string_multiple (buffer, buffer_len, - ds, vl)); - - tt = CDTIME_T_TO_TIME_T (vl->time); - switch (ds->ds[0].type) - { - case DS_TYPE_DERIVE: - status = ssnprintf (buffer, buffer_len, "%u:%"PRIi64, - (unsigned) tt, vl->values[0].derive); - break; - case DS_TYPE_GAUGE: - status = ssnprintf (buffer, buffer_len, "%u:"GAUGE_FORMAT, - (unsigned) tt, vl->values[0].gauge); - break; - case DS_TYPE_COUNTER: - status = ssnprintf (buffer, buffer_len, "%u:%llu", - (unsigned) tt, vl->values[0].counter); - break; - case DS_TYPE_ABSOLUTE: - status = ssnprintf (buffer, buffer_len, "%u:%"PRIu64, - (unsigned) tt, vl->values[0].absolute); - break; - default: - return (EINVAL); - } - - if ((status < 1) || (status >= buffer_len)) - return (ENOMEM); - - return (0); +static int value_list_to_string(char *buffer, int buffer_len, + const data_set_t *ds, const value_list_t *vl) { + int status; + time_t tt; + + if (ds->ds_num != 1) + return value_list_to_string_multiple(buffer, buffer_len, ds, vl); + + tt = CDTIME_T_TO_TIME_T(vl->time); + switch (ds->ds[0].type) { + case DS_TYPE_DERIVE: + status = snprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt, + vl->values[0].derive); + break; + case DS_TYPE_GAUGE: + status = snprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt, + vl->values[0].gauge); + break; + case DS_TYPE_COUNTER: + status = snprintf(buffer, buffer_len, "%u:%llu", (unsigned)tt, + vl->values[0].counter); + break; + case DS_TYPE_ABSOLUTE: + status = snprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt, + vl->values[0].absolute); + break; + default: + return EINVAL; + } + + if ((status < 1) || (status >= buffer_len)) + return ENOMEM; + + return 0; } /* int value_list_to_string */ -static int value_list_to_filename (char *buffer, size_t buffer_size, - value_list_t const *vl) -{ - char const suffix[] = ".rrd"; - int status; - size_t len; +static int value_list_to_filename(char *buffer, size_t buffer_size, + value_list_t const *vl) { + char const suffix[] = ".rrd"; + int status; + size_t len; - if (datadir != NULL) - { - size_t datadir_len = strlen (datadir) + 1; + if (datadir != NULL) { + size_t datadir_len = strlen(datadir) + 1; - if (datadir_len >= buffer_size) - return (ENOMEM); + if (datadir_len >= buffer_size) + return ENOMEM; - sstrncpy (buffer, datadir, buffer_size); - buffer[datadir_len - 1] = '/'; - buffer[datadir_len] = 0; + sstrncpy(buffer, datadir, buffer_size); + buffer[datadir_len - 1] = '/'; + buffer[datadir_len] = 0; - buffer += datadir_len; - buffer_size -= datadir_len; - } + buffer += datadir_len; + buffer_size -= datadir_len; + } - status = FORMAT_VL (buffer, buffer_size, vl); - if (status != 0) - return (status); + status = FORMAT_VL(buffer, buffer_size, vl); + if (status != 0) + return status; - len = strlen (buffer); - assert (len < buffer_size); - buffer += len; - buffer_size -= len; + len = strlen(buffer); + assert(len < buffer_size); + buffer += len; + buffer_size -= len; - if (buffer_size <= sizeof (suffix)) - return (ENOMEM); + if (buffer_size <= sizeof(suffix)) + return ENOMEM; - memcpy (buffer, suffix, sizeof (suffix)); - return (0); + memcpy(buffer, suffix, sizeof(suffix)); + return 0; } /* int value_list_to_filename */ -static void *rrd_queue_thread (void __attribute__((unused)) *data) -{ - struct timeval tv_next_update; - struct timeval tv_now; - - gettimeofday (&tv_next_update, /* timezone = */ NULL); - - while (42) - { - rrd_queue_t *queue_entry; - rrd_cache_t *cache_entry; - char **values; - int values_num; - int status; - - values = NULL; - values_num = 0; - - pthread_mutex_lock (&queue_lock); - /* Wait for values to arrive */ - while (42) - { - struct timespec ts_wait; - - while ((flushq_head == NULL) && (queue_head == NULL) - && (do_shutdown == 0)) - pthread_cond_wait (&queue_cond, &queue_lock); - - if ((flushq_head == NULL) && (queue_head == NULL)) - break; - - /* Don't delay if there's something to flush */ - if (flushq_head != NULL) - break; - - /* Don't delay if we're shutting down */ - if (do_shutdown != 0) - break; - - /* Don't delay if no delay was configured. */ - if (write_rate <= 0.0) - break; - - gettimeofday (&tv_now, /* timezone = */ NULL); - status = timeval_cmp (tv_next_update, tv_now, NULL); - /* We're good to go */ - if (status <= 0) - break; - - /* We're supposed to wait a bit with this update, so we'll - * wait for the next addition to the queue or to the end of - * the wait period - whichever comes first. */ - ts_wait.tv_sec = tv_next_update.tv_sec; - ts_wait.tv_nsec = 1000 * tv_next_update.tv_usec; - - status = pthread_cond_timedwait (&queue_cond, &queue_lock, - &ts_wait); - if (status == ETIMEDOUT) - break; - } /* while (42) */ - - /* XXX: If you need to lock both, cache_lock and queue_lock, at - * the same time, ALWAYS lock `cache_lock' first! */ - - /* We're in the shutdown phase */ - if ((flushq_head == NULL) && (queue_head == NULL)) - { - pthread_mutex_unlock (&queue_lock); - break; - } - - if (flushq_head != NULL) - { - /* Dequeue the first flush entry */ - queue_entry = flushq_head; - if (flushq_head == flushq_tail) - flushq_head = flushq_tail = NULL; - else - flushq_head = flushq_head->next; - } - else /* if (queue_head != NULL) */ - { - /* Dequeue the first regular entry */ - queue_entry = queue_head; - if (queue_head == queue_tail) - queue_head = queue_tail = NULL; - else - queue_head = queue_head->next; - } - - /* Unlock the queue again */ - pthread_mutex_unlock (&queue_lock); - - /* We now need the cache lock so the entry isn't updated while - * we make a copy of its values */ - pthread_mutex_lock (&cache_lock); - - status = c_avl_get (cache, queue_entry->filename, - (void *) &cache_entry); - - if (status == 0) - { - values = cache_entry->values; - values_num = cache_entry->values_num; - - cache_entry->values = NULL; - cache_entry->values_num = 0; - cache_entry->flags = FLAG_NONE; - } - - pthread_mutex_unlock (&cache_lock); - - if (status != 0) - { - sfree (queue_entry->filename); - sfree (queue_entry); - continue; - } - - /* Update `tv_next_update' */ - if (write_rate > 0.0) - { - gettimeofday (&tv_now, /* timezone = */ NULL); - tv_next_update.tv_sec = tv_now.tv_sec; - tv_next_update.tv_usec = tv_now.tv_usec - + ((suseconds_t) (1000000 * write_rate)); - while (tv_next_update.tv_usec > 1000000) - { - tv_next_update.tv_sec++; - tv_next_update.tv_usec -= 1000000; - } - } - - /* Write the values to the RRD-file */ - srrd_update (queue_entry->filename, NULL, - values_num, (const char **)values); - DEBUG ("rrdtool plugin: queue thread: Wrote %i value%s to %s", - values_num, (values_num == 1) ? "" : "s", - queue_entry->filename); - - for (int i = 0; i < values_num; i++) - { - sfree (values[i]); - } - sfree (values); - sfree (queue_entry->filename); - sfree (queue_entry); - } /* while (42) */ - - pthread_exit ((void *) 0); - return ((void *) 0); +static void *rrd_queue_thread(void __attribute__((unused)) * data) { + struct timeval tv_next_update; + struct timeval tv_now; + + gettimeofday(&tv_next_update, /* timezone = */ NULL); + + while (42) { + rrd_queue_t *queue_entry; + rrd_cache_t *cache_entry; + char **values; + int values_num; + int status; + + values = NULL; + values_num = 0; + + pthread_mutex_lock(&queue_lock); + /* Wait for values to arrive */ + while (42) { + struct timespec ts_wait; + + while ((flushq_head == NULL) && (queue_head == NULL) && + (do_shutdown == 0)) + pthread_cond_wait(&queue_cond, &queue_lock); + + if ((flushq_head == NULL) && (queue_head == NULL)) + break; + + /* Don't delay if there's something to flush */ + if (flushq_head != NULL) + break; + + /* Don't delay if we're shutting down */ + if (do_shutdown != 0) + break; + + /* Don't delay if no delay was configured. */ + if (write_rate <= 0.0) + break; + + gettimeofday(&tv_now, /* timezone = */ NULL); + status = timeval_cmp(tv_next_update, tv_now, NULL); + /* We're good to go */ + if (status <= 0) + break; + + /* We're supposed to wait a bit with this update, so we'll + * wait for the next addition to the queue or to the end of + * the wait period - whichever comes first. */ + ts_wait.tv_sec = tv_next_update.tv_sec; + ts_wait.tv_nsec = 1000 * tv_next_update.tv_usec; + + status = pthread_cond_timedwait(&queue_cond, &queue_lock, &ts_wait); + if (status == ETIMEDOUT) + break; + } /* while (42) */ + + /* XXX: If you need to lock both, cache_lock and queue_lock, at + * the same time, ALWAYS lock `cache_lock' first! */ + + /* We're in the shutdown phase */ + if ((flushq_head == NULL) && (queue_head == NULL)) { + pthread_mutex_unlock(&queue_lock); + break; + } + + if (flushq_head != NULL) { + /* Dequeue the first flush entry */ + queue_entry = flushq_head; + if (flushq_head == flushq_tail) + flushq_head = flushq_tail = NULL; + else + flushq_head = flushq_head->next; + } else /* if (queue_head != NULL) */ + { + /* Dequeue the first regular entry */ + queue_entry = queue_head; + if (queue_head == queue_tail) + queue_head = queue_tail = NULL; + else + queue_head = queue_head->next; + } + + /* Unlock the queue again */ + pthread_mutex_unlock(&queue_lock); + + /* We now need the cache lock so the entry isn't updated while + * we make a copy of its values */ + pthread_mutex_lock(&cache_lock); + + status = c_avl_get(cache, queue_entry->filename, (void *)&cache_entry); + + if (status == 0) { + values = cache_entry->values; + values_num = cache_entry->values_num; + + cache_entry->values = NULL; + cache_entry->values_num = 0; + cache_entry->flags = FLAG_NONE; + } + + pthread_mutex_unlock(&cache_lock); + + if (status != 0) { + sfree(queue_entry->filename); + sfree(queue_entry); + continue; + } + + /* Update `tv_next_update' */ + if (write_rate > 0.0) { + gettimeofday(&tv_now, /* timezone = */ NULL); + tv_next_update.tv_sec = tv_now.tv_sec; + tv_next_update.tv_usec = + tv_now.tv_usec + ((suseconds_t)(1000000 * write_rate)); + while (tv_next_update.tv_usec > 1000000) { + tv_next_update.tv_sec++; + tv_next_update.tv_usec -= 1000000; + } + } + + /* Write the values to the RRD-file */ + srrd_update(queue_entry->filename, NULL, values_num, (const char **)values); + DEBUG("rrdtool plugin: queue thread: Wrote %i value%s to %s", values_num, + (values_num == 1) ? "" : "s", queue_entry->filename); + + for (int i = 0; i < values_num; i++) { + sfree(values[i]); + } + sfree(values); + sfree(queue_entry->filename); + sfree(queue_entry); + } /* while (42) */ + + pthread_exit((void *)0); + return (void *)0; } /* void *rrd_queue_thread */ -static int rrd_queue_enqueue (const char *filename, - rrd_queue_t **head, rrd_queue_t **tail) -{ +static int rrd_queue_enqueue(const char *filename, rrd_queue_t **head, + rrd_queue_t **tail) { rrd_queue_t *queue_entry; - queue_entry = malloc (sizeof (*queue_entry)); + queue_entry = malloc(sizeof(*queue_entry)); if (queue_entry == NULL) - return (-1); + return -1; - queue_entry->filename = strdup (filename); - if (queue_entry->filename == NULL) - { - free (queue_entry); - return (-1); + queue_entry->filename = strdup(filename); + if (queue_entry->filename == NULL) { + free(queue_entry); + return -1; } queue_entry->next = NULL; - pthread_mutex_lock (&queue_lock); + pthread_mutex_lock(&queue_lock); if (*tail == NULL) *head = queue_entry; @@ -496,36 +441,33 @@ static int rrd_queue_enqueue (const char *filename, (*tail)->next = queue_entry; *tail = queue_entry; - pthread_cond_signal (&queue_cond); - pthread_mutex_unlock (&queue_lock); + pthread_cond_signal(&queue_cond); + pthread_mutex_unlock(&queue_lock); - return (0); + return 0; } /* int rrd_queue_enqueue */ -static int rrd_queue_dequeue (const char *filename, - rrd_queue_t **head, rrd_queue_t **tail) -{ +static int rrd_queue_dequeue(const char *filename, rrd_queue_t **head, + rrd_queue_t **tail) { rrd_queue_t *this; rrd_queue_t *prev; - pthread_mutex_lock (&queue_lock); + pthread_mutex_lock(&queue_lock); prev = NULL; this = *head; - while (this != NULL) - { - if (strcmp (this->filename, filename) == 0) + while (this != NULL) { + if (strcmp(this->filename, filename) == 0) break; prev = this; this = this->next; } - if (this == NULL) - { - pthread_mutex_unlock (&queue_lock); - return (-1); + if (this == NULL) { + pthread_mutex_unlock(&queue_lock); + return -1; } if (prev == NULL) @@ -536,326 +478,274 @@ static int rrd_queue_dequeue (const char *filename, if (this->next == NULL) *tail = prev; - pthread_mutex_unlock (&queue_lock); + pthread_mutex_unlock(&queue_lock); - sfree (this->filename); - sfree (this); + sfree(this->filename); + sfree(this); - return (0); + return 0; } /* int rrd_queue_dequeue */ /* XXX: You must hold "cache_lock" when calling this function! */ -static void rrd_cache_flush (cdtime_t timeout) -{ - rrd_cache_t *rc; - cdtime_t now; - - char **keys = NULL; - int keys_num = 0; - - char *key; - c_avl_iterator_t *iter; - - DEBUG ("rrdtool plugin: Flushing cache, timeout = %.3f", - CDTIME_T_TO_DOUBLE (timeout)); - - now = cdtime (); - timeout = TIME_T_TO_CDTIME_T (timeout); - - /* Build a list of entries to be flushed */ - iter = c_avl_get_iterator (cache); - while (c_avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0) - { - if (rc->flags != FLAG_NONE) - continue; - /* timeout == 0 => flush everything */ - else if ((timeout != 0) - && ((now - rc->first_value) < timeout)) - continue; - else if (rc->values_num > 0) - { - int status; - - status = rrd_queue_enqueue (key, &queue_head, &queue_tail); - if (status == 0) - rc->flags = FLAG_QUEUED; - } - else /* ancient and no values -> waste of memory */ - { - char **tmp = realloc (keys, - (keys_num + 1) * sizeof (char *)); - if (tmp == NULL) - { - char errbuf[1024]; - ERROR ("rrdtool plugin: " - "realloc failed: %s", - sstrerror (errno, errbuf, - sizeof (errbuf))); - c_avl_iterator_destroy (iter); - sfree (keys); - return; - } - keys = tmp; - keys[keys_num] = key; - keys_num++; - } - } /* while (c_avl_iterator_next) */ - c_avl_iterator_destroy (iter); - - for (int i = 0; i < keys_num; i++) - { - if (c_avl_remove (cache, keys[i], (void *) &key, (void *) &rc) != 0) - { - DEBUG ("rrdtool plugin: c_avl_remove (%s) failed.", keys[i]); - continue; - } - - assert (rc->values == NULL); - assert (rc->values_num == 0); - - sfree (rc); - sfree (key); - keys[i] = NULL; - } /* for (i = 0..keys_num) */ - - sfree (keys); - - cache_flush_last = now; +static void rrd_cache_flush(cdtime_t timeout) { + rrd_cache_t *rc; + cdtime_t now; + + char **keys = NULL; + int keys_num = 0; + + char *key; + c_avl_iterator_t *iter; + + DEBUG("rrdtool plugin: Flushing cache, timeout = %.3f", + CDTIME_T_TO_DOUBLE(timeout)); + + now = cdtime(); + + /* Build a list of entries to be flushed */ + iter = c_avl_get_iterator(cache); + while (c_avl_iterator_next(iter, (void *)&key, (void *)&rc) == 0) { + if (rc->flags != FLAG_NONE) + continue; + /* timeout == 0 => flush everything */ + else if ((timeout != 0) && ((now - rc->first_value) < timeout)) + continue; + else if (rc->values_num > 0) { + int status; + + status = rrd_queue_enqueue(key, &queue_head, &queue_tail); + if (status == 0) + rc->flags = FLAG_QUEUED; + } else /* ancient and no values -> waste of memory */ + { + char **tmp = realloc(keys, (keys_num + 1) * sizeof(char *)); + if (tmp == NULL) { + char errbuf[1024]; + ERROR("rrdtool plugin: " + "realloc failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + c_avl_iterator_destroy(iter); + sfree(keys); + return; + } + keys = tmp; + keys[keys_num] = key; + keys_num++; + } + } /* while (c_avl_iterator_next) */ + c_avl_iterator_destroy(iter); + + for (int i = 0; i < keys_num; i++) { + if (c_avl_remove(cache, keys[i], (void *)&key, (void *)&rc) != 0) { + DEBUG("rrdtool plugin: c_avl_remove (%s) failed.", keys[i]); + continue; + } + + assert(rc->values == NULL); + assert(rc->values_num == 0); + + sfree(rc); + sfree(key); + keys[i] = NULL; + } /* for (i = 0..keys_num) */ + + sfree(keys); + + cache_flush_last = now; } /* void rrd_cache_flush */ -static int rrd_cache_flush_identifier (cdtime_t timeout, - const char *identifier) -{ +static int rrd_cache_flush_identifier(cdtime_t timeout, + const char *identifier) { rrd_cache_t *rc; cdtime_t now; int status; char key[2048]; - if (identifier == NULL) - { - rrd_cache_flush (timeout); - return (0); + if (identifier == NULL) { + rrd_cache_flush(timeout); + return 0; } - now = cdtime (); + now = cdtime(); if (datadir == NULL) - snprintf (key, sizeof (key), "%s.rrd", - identifier); + snprintf(key, sizeof(key), "%s.rrd", identifier); else - snprintf (key, sizeof (key), "%s/%s.rrd", - datadir, identifier); - key[sizeof (key) - 1] = 0; - - status = c_avl_get (cache, key, (void *) &rc); - if (status != 0) - { - INFO ("rrdtool plugin: rrd_cache_flush_identifier: " - "c_avl_get (%s) failed. Does that file really exist?", - key); - return (status); + snprintf(key, sizeof(key), "%s/%s.rrd", datadir, identifier); + key[sizeof(key) - 1] = 0; + + status = c_avl_get(cache, key, (void *)&rc); + if (status != 0) { + INFO("rrdtool plugin: rrd_cache_flush_identifier: " + "c_avl_get (%s) failed. Does that file really exist?", + key); + return status; } - if (rc->flags == FLAG_FLUSHQ) - { + if (rc->flags == FLAG_FLUSHQ) { status = 0; - } - else if (rc->flags == FLAG_QUEUED) - { - rrd_queue_dequeue (key, &queue_head, &queue_tail); - status = rrd_queue_enqueue (key, &flushq_head, &flushq_tail); + } else if (rc->flags == FLAG_QUEUED) { + rrd_queue_dequeue(key, &queue_head, &queue_tail); + status = rrd_queue_enqueue(key, &flushq_head, &flushq_tail); if (status == 0) rc->flags = FLAG_FLUSHQ; - } - else if ((now - rc->first_value) < timeout) - { + } else if ((now - rc->first_value) < timeout) { status = 0; - } - else if (rc->values_num > 0) - { - status = rrd_queue_enqueue (key, &flushq_head, &flushq_tail); + } else if (rc->values_num > 0) { + status = rrd_queue_enqueue(key, &flushq_head, &flushq_tail); if (status == 0) rc->flags = FLAG_FLUSHQ; } - return (status); + return status; } /* int rrd_cache_flush_identifier */ -static int64_t rrd_get_random_variation (void) -{ - long min; - long max; - +static int64_t rrd_get_random_variation(void) { if (random_timeout == 0) - return (0); + return 0; - /* Assure that "cache_timeout + random_variation" is never negative. */ - if (random_timeout > cache_timeout) - { - INFO ("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.", - CDTIME_T_TO_DOUBLE (cache_timeout)); - random_timeout = cache_timeout; + return (int64_t)cdrand_range(-random_timeout, random_timeout); +} /* int64_t rrd_get_random_variation */ + +static int rrd_cache_insert(const char *filename, const char *value, + cdtime_t value_time) { + rrd_cache_t *rc = NULL; + int new_rc = 0; + char **values_new; + + pthread_mutex_lock(&cache_lock); + + /* This shouldn't happen, but it did happen at least once, so we'll be + * careful. */ + if (cache == NULL) { + pthread_mutex_unlock(&cache_lock); + WARNING("rrdtool plugin: cache == NULL."); + return -1; } - max = (long) (random_timeout / 2); - min = max - ((long) random_timeout); + int status = c_avl_get(cache, filename, (void *)&rc); + if ((status != 0) || (rc == NULL)) { + rc = malloc(sizeof(*rc)); + if (rc == NULL) { + pthread_mutex_unlock(&cache_lock); + return -1; + } + rc->values_num = 0; + rc->values = NULL; + rc->first_value = 0; + rc->last_value = 0; + rc->random_variation = rrd_get_random_variation(); + rc->flags = FLAG_NONE; + new_rc = 1; + } - return ((int64_t) cdrand_range (min, max)); -} /* int64_t rrd_get_random_variation */ + assert(value_time > 0); /* plugin_dispatch() ensures this. */ + if (rc->last_value >= value_time) { + pthread_mutex_unlock(&cache_lock); + DEBUG("rrdtool plugin: (rc->last_value = %" PRIu64 ") " + ">= (value_time = %" PRIu64 ")", + rc->last_value, value_time); + return -1; + } -static int rrd_cache_insert (const char *filename, - const char *value, cdtime_t value_time) -{ - rrd_cache_t *rc = NULL; - int new_rc = 0; - char **values_new; - - pthread_mutex_lock (&cache_lock); - - /* This shouldn't happen, but it did happen at least once, so we'll be - * careful. */ - if (cache == NULL) - { - pthread_mutex_unlock (&cache_lock); - WARNING ("rrdtool plugin: cache == NULL."); - return (-1); - } - - c_avl_get (cache, filename, (void *) &rc); - - if (rc == NULL) - { - rc = malloc (sizeof (*rc)); - if (rc == NULL) - { - pthread_mutex_unlock (&cache_lock); - return (-1); - } - rc->values_num = 0; - rc->values = NULL; - rc->first_value = 0; - rc->last_value = 0; - rc->random_variation = rrd_get_random_variation (); - rc->flags = FLAG_NONE; - new_rc = 1; - } - - assert (value_time > 0); /* plugin_dispatch() ensures this. */ - if (rc->last_value >= value_time) - { - pthread_mutex_unlock (&cache_lock); - DEBUG ("rrdtool plugin: (rc->last_value = %"PRIu64") " - ">= (value_time = %"PRIu64")", - rc->last_value, value_time); - return (-1); - } - - values_new = realloc ((void *) rc->values, - (rc->values_num + 1) * sizeof (char *)); - if (values_new == NULL) - { - char errbuf[1024]; - void *cache_key = NULL; - - sstrerror (errno, errbuf, sizeof (errbuf)); - - c_avl_remove (cache, filename, &cache_key, NULL); - pthread_mutex_unlock (&cache_lock); - - ERROR ("rrdtool plugin: realloc failed: %s", errbuf); - - sfree (cache_key); - sfree (rc->values); - sfree (rc); - return (-1); - } - rc->values = values_new; - - rc->values[rc->values_num] = strdup (value); - if (rc->values[rc->values_num] != NULL) - rc->values_num++; - - if (rc->values_num == 1) - rc->first_value = value_time; - rc->last_value = value_time; - - /* Insert if this is the first value */ - if (new_rc == 1) - { - void *cache_key = strdup (filename); - - if (cache_key == NULL) - { - char errbuf[1024]; - sstrerror (errno, errbuf, sizeof (errbuf)); - - pthread_mutex_unlock (&cache_lock); - - ERROR ("rrdtool plugin: strdup failed: %s", errbuf); - - sfree (rc->values[0]); - sfree (rc->values); - sfree (rc); - return (-1); - } - - c_avl_insert (cache, cache_key, rc); - } - - DEBUG ("rrdtool plugin: rrd_cache_insert: file = %s; " - "values_num = %i; age = %.3f;", - filename, rc->values_num, - CDTIME_T_TO_DOUBLE (rc->last_value - rc->first_value)); - - if ((rc->last_value - rc->first_value) >= (cache_timeout + rc->random_variation)) - { - /* XXX: If you need to lock both, cache_lock and queue_lock, at - * the same time, ALWAYS lock `cache_lock' first! */ - if (rc->flags == FLAG_NONE) - { - int status; - - status = rrd_queue_enqueue (filename, &queue_head, &queue_tail); - if (status == 0) - rc->flags = FLAG_QUEUED; - - rc->random_variation = rrd_get_random_variation (); - } - else - { - DEBUG ("rrdtool plugin: `%s' is already queued.", filename); - } - } - - if ((cache_timeout > 0) && - ((cdtime () - cache_flush_last) > cache_flush_timeout)) - rrd_cache_flush (cache_flush_timeout); - - pthread_mutex_unlock (&cache_lock); - - return (0); + values_new = + realloc((void *)rc->values, (rc->values_num + 1) * sizeof(char *)); + if (values_new == NULL) { + char errbuf[1024]; + void *cache_key = NULL; + + sstrerror(errno, errbuf, sizeof(errbuf)); + + c_avl_remove(cache, filename, &cache_key, NULL); + pthread_mutex_unlock(&cache_lock); + + ERROR("rrdtool plugin: realloc failed: %s", errbuf); + + sfree(cache_key); + sfree(rc->values); + sfree(rc); + return -1; + } + rc->values = values_new; + + rc->values[rc->values_num] = strdup(value); + if (rc->values[rc->values_num] != NULL) + rc->values_num++; + + if (rc->values_num == 1) + rc->first_value = value_time; + rc->last_value = value_time; + + /* Insert if this is the first value */ + if (new_rc == 1) { + void *cache_key = strdup(filename); + + if (cache_key == NULL) { + char errbuf[1024]; + sstrerror(errno, errbuf, sizeof(errbuf)); + + pthread_mutex_unlock(&cache_lock); + + ERROR("rrdtool plugin: strdup failed: %s", errbuf); + + sfree(rc->values[0]); + sfree(rc->values); + sfree(rc); + return -1; + } + + c_avl_insert(cache, cache_key, rc); + } + + DEBUG("rrdtool plugin: rrd_cache_insert: file = %s; " + "values_num = %i; age = %.3f;", + filename, rc->values_num, + CDTIME_T_TO_DOUBLE(rc->last_value - rc->first_value)); + + if ((rc->last_value - rc->first_value) >= + (cache_timeout + rc->random_variation)) { + /* XXX: If you need to lock both, cache_lock and queue_lock, at + * the same time, ALWAYS lock `cache_lock' first! */ + if (rc->flags == FLAG_NONE) { + int status; + + status = rrd_queue_enqueue(filename, &queue_head, &queue_tail); + if (status == 0) + rc->flags = FLAG_QUEUED; + + rc->random_variation = rrd_get_random_variation(); + } else { + DEBUG("rrdtool plugin: `%s' is already queued.", filename); + } + } + + if ((cache_timeout > 0) && + ((cdtime() - cache_flush_last) > cache_flush_timeout)) + rrd_cache_flush(cache_timeout + random_timeout); + + pthread_mutex_unlock(&cache_lock); + + return 0; } /* int rrd_cache_insert */ -static int rrd_cache_destroy (void) /* {{{ */ +static int rrd_cache_destroy(void) /* {{{ */ { void *key = NULL; void *value = NULL; int non_empty = 0; - pthread_mutex_lock (&cache_lock); + pthread_mutex_lock(&cache_lock); - if (cache == NULL) - { - pthread_mutex_unlock (&cache_lock); - return (0); + if (cache == NULL) { + pthread_mutex_unlock(&cache_lock); + return 0; } - while (c_avl_pick (cache, &key, &value) == 0) - { + while (c_avl_pick(cache, &key, &value) == 0) { rrd_cache_t *rc; - sfree (key); + sfree(key); key = NULL; rc = value; @@ -865,395 +755,335 @@ static int rrd_cache_destroy (void) /* {{{ */ non_empty++; for (int i = 0; i < rc->values_num; i++) - sfree (rc->values[i]); - sfree (rc->values); - sfree (rc); + sfree(rc->values[i]); + sfree(rc->values); + sfree(rc); } - c_avl_destroy (cache); + c_avl_destroy(cache); cache = NULL; - if (non_empty > 0) - { - INFO ("rrdtool plugin: %i cache %s had values when destroying the cache.", - non_empty, (non_empty == 1) ? "entry" : "entries"); - } - else - { - DEBUG ("rrdtool plugin: No values have been lost " - "when destroying the cache."); + if (non_empty > 0) { + INFO("rrdtool plugin: %i cache %s had values when destroying the cache.", + non_empty, (non_empty == 1) ? "entry" : "entries"); + } else { + DEBUG("rrdtool plugin: No values have been lost " + "when destroying the cache."); } - pthread_mutex_unlock (&cache_lock); - return (0); + pthread_mutex_unlock(&cache_lock); + return 0; } /* }}} int rrd_cache_destroy */ -static int rrd_compare_numeric (const void *a_ptr, const void *b_ptr) -{ - int a = *((int *) a_ptr); - int b = *((int *) b_ptr); - - if (a < b) - return (-1); - else if (a > b) - return (1); - else - return (0); +static int rrd_compare_numeric(const void *a_ptr, const void *b_ptr) { + int a = *((int *)a_ptr); + int b = *((int *)b_ptr); + + if (a < b) + return -1; + else if (a > b) + return 1; + else + return 0; } /* int rrd_compare_numeric */ -static int rrd_write (const data_set_t *ds, const value_list_t *vl, - user_data_t __attribute__((unused)) *user_data) -{ - struct stat statbuf; - char filename[512]; - char values[512]; - int status; - - if (do_shutdown) - return (0); - - if (0 != strcmp (ds->type, vl->type)) { - ERROR ("rrdtool plugin: DS type does not match value list type"); - return -1; - } - - if (value_list_to_filename (filename, sizeof (filename), vl) != 0) - return (-1); - - if (value_list_to_string (values, sizeof (values), ds, vl) != 0) - return (-1); - - if (stat (filename, &statbuf) == -1) - { - if (errno == ENOENT) - { - status = cu_rrd_create_file (filename, - ds, vl, &rrdcreate_config); - if (status != 0) - return (-1); - else if (rrdcreate_config.async) - return (0); - } - else - { - char errbuf[1024]; - ERROR ("stat(%s) failed: %s", filename, - sstrerror (errno, errbuf, - sizeof (errbuf))); - return (-1); - } - } - else if (!S_ISREG (statbuf.st_mode)) - { - ERROR ("stat(%s): Not a regular file!", - filename); - return (-1); - } - - status = rrd_cache_insert (filename, values, vl->time); - - return (status); +static int rrd_write(const data_set_t *ds, const value_list_t *vl, + user_data_t __attribute__((unused)) * user_data) { + + if (do_shutdown) + return 0; + + if (0 != strcmp(ds->type, vl->type)) { + ERROR("rrdtool plugin: DS type does not match value list type"); + return -1; + } + + char filename[PATH_MAX]; + if (value_list_to_filename(filename, sizeof(filename), vl) != 0) + return -1; + + char values[32 * (ds->ds_num + 1)]; + if (value_list_to_string(values, sizeof(values), ds, vl) != 0) + return -1; + + struct stat statbuf = {0}; + if (stat(filename, &statbuf) == -1) { + if (errno == ENOENT) { + if (cu_rrd_create_file(filename, ds, vl, &rrdcreate_config) != 0) { + return -1; + } else if (rrdcreate_config.async) { + return 0; + } + } else { + char errbuf[1024]; + ERROR("rrdtool plugin: stat(%s) failed: %s", filename, + sstrerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + } else if (!S_ISREG(statbuf.st_mode)) { + ERROR("rrdtool plugin: stat(%s): Not a regular file!", filename); + return -1; + } + + return rrd_cache_insert(filename, values, vl->time); } /* int rrd_write */ -static int rrd_flush (cdtime_t timeout, const char *identifier, - __attribute__((unused)) user_data_t *user_data) -{ - pthread_mutex_lock (&cache_lock); +static int rrd_flush(cdtime_t timeout, const char *identifier, + __attribute__((unused)) user_data_t *user_data) { + pthread_mutex_lock(&cache_lock); - if (cache == NULL) { - pthread_mutex_unlock (&cache_lock); - return (0); - } + if (cache == NULL) { + pthread_mutex_unlock(&cache_lock); + return 0; + } - rrd_cache_flush_identifier (timeout, identifier); + rrd_cache_flush_identifier(timeout, identifier); - pthread_mutex_unlock (&cache_lock); - return (0); + pthread_mutex_unlock(&cache_lock); + return 0; } /* int rrd_flush */ -static int rrd_config (const char *key, const char *value) -{ - if (strcasecmp ("CacheTimeout", key) == 0) - { - double tmp = atof (value); - if (tmp < 0) - { - fprintf (stderr, "rrdtool: `CacheTimeout' must " - "be greater than 0.\n"); - ERROR ("rrdtool: `CacheTimeout' must " - "be greater than 0.\n"); - return (1); - } - cache_timeout = DOUBLE_TO_CDTIME_T (tmp); - } - else if (strcasecmp ("CacheFlush", key) == 0) - { - int tmp = atoi (value); - if (tmp < 0) - { - fprintf (stderr, "rrdtool: `CacheFlush' must " - "be greater than 0.\n"); - ERROR ("rrdtool: `CacheFlush' must " - "be greater than 0.\n"); - return (1); - } - cache_flush_timeout = tmp; - } - else if (strcasecmp ("DataDir", key) == 0) - { - char *tmp; - size_t len; - - tmp = strdup (value); - if (tmp == NULL) - { - ERROR ("rrdtool plugin: strdup failed."); - return (1); - } - - len = strlen (tmp); - while ((len > 0) && (tmp[len - 1] == '/')) - { - len--; - tmp[len] = 0; - } - - if (len == 0) - { - ERROR ("rrdtool plugin: Invalid \"DataDir\" option."); - sfree (tmp); - return (1); - } - - if (datadir != NULL) - { - sfree (datadir); - } - - datadir = tmp; - } - else if (strcasecmp ("StepSize", key) == 0) - { - unsigned long temp = strtoul (value, NULL, 0); - if (temp > 0) - rrdcreate_config.stepsize = temp; - } - else if (strcasecmp ("HeartBeat", key) == 0) - { - int temp = atoi (value); - if (temp > 0) - rrdcreate_config.heartbeat = temp; - } - else if (strcasecmp ("CreateFilesAsync", key) == 0) - { - if (IS_TRUE (value)) - rrdcreate_config.async = 1; - else - rrdcreate_config.async = 0; - } - else if (strcasecmp ("RRARows", key) == 0) - { - int tmp = atoi (value); - if (tmp <= 0) - { - fprintf (stderr, "rrdtool: `RRARows' must " - "be greater than 0.\n"); - ERROR ("rrdtool: `RRARows' must " - "be greater than 0.\n"); - return (1); - } - rrdcreate_config.rrarows = tmp; - } - else if (strcasecmp ("RRATimespan", key) == 0) - { - char *saveptr = NULL; - char *dummy; - char *ptr; - char *value_copy; - int *tmp_alloc; - - value_copy = strdup (value); - if (value_copy == NULL) - return (1); - - dummy = value_copy; - while ((ptr = strtok_r (dummy, ", \t", &saveptr)) != NULL) - { - dummy = NULL; - - tmp_alloc = realloc (rrdcreate_config.timespans, - sizeof (int) * (rrdcreate_config.timespans_num + 1)); - if (tmp_alloc == NULL) - { - fprintf (stderr, "rrdtool: realloc failed.\n"); - ERROR ("rrdtool: realloc failed.\n"); - free (value_copy); - return (1); - } - rrdcreate_config.timespans = tmp_alloc; - rrdcreate_config.timespans[rrdcreate_config.timespans_num] = atoi (ptr); - if (rrdcreate_config.timespans[rrdcreate_config.timespans_num] != 0) - rrdcreate_config.timespans_num++; - } /* while (strtok_r) */ - - qsort (/* base = */ rrdcreate_config.timespans, - /* nmemb = */ rrdcreate_config.timespans_num, - /* size = */ sizeof (rrdcreate_config.timespans[0]), - /* compar = */ rrd_compare_numeric); - - free (value_copy); - } - else if (strcasecmp ("XFF", key) == 0) - { - double tmp = atof (value); - if ((tmp < 0.0) || (tmp >= 1.0)) - { - fprintf (stderr, "rrdtool: `XFF' must " - "be in the range 0 to 1 (exclusive)."); - ERROR ("rrdtool: `XFF' must " - "be in the range 0 to 1 (exclusive)."); - return (1); - } - rrdcreate_config.xff = tmp; - } - else if (strcasecmp ("WritesPerSecond", key) == 0) - { - double wps = atof (value); - - if (wps < 0.0) - { - fprintf (stderr, "rrdtool: `WritesPerSecond' must be " - "greater than or equal to zero."); - return (1); - } - else if (wps == 0.0) - { - write_rate = 0.0; - } - else - { - write_rate = 1.0 / wps; - } - } - else if (strcasecmp ("RandomTimeout", key) == 0) - { - double tmp; - - tmp = atof (value); - if (tmp < 0.0) - { - fprintf (stderr, "rrdtool: `RandomTimeout' must " - "be greater than or equal to zero.\n"); - ERROR ("rrdtool: `RandomTimeout' must " - "be greater then or equal to zero."); - } - else - { - random_timeout = DOUBLE_TO_CDTIME_T (tmp); - } - } - else - { - return (-1); - } - return (0); +static int rrd_config(const char *key, const char *value) { + if (strcasecmp("CacheTimeout", key) == 0) { + double tmp = atof(value); + if (tmp < 0) { + fprintf(stderr, "rrdtool: `CacheTimeout' must " + "be greater than 0.\n"); + ERROR("rrdtool: `CacheTimeout' must " + "be greater than 0.\n"); + return 1; + } + cache_timeout = DOUBLE_TO_CDTIME_T(tmp); + } else if (strcasecmp("CacheFlush", key) == 0) { + double tmp = atof(value); + if (tmp < 0) { + fprintf(stderr, "rrdtool: `CacheFlush' must " + "be greater than 0.\n"); + ERROR("rrdtool: `CacheFlush' must " + "be greater than 0.\n"); + return 1; + } + cache_flush_timeout = DOUBLE_TO_CDTIME_T(tmp); + } else if (strcasecmp("DataDir", key) == 0) { + char *tmp; + size_t len; + + tmp = strdup(value); + if (tmp == NULL) { + ERROR("rrdtool plugin: strdup failed."); + return 1; + } + + len = strlen(tmp); + while ((len > 0) && (tmp[len - 1] == '/')) { + len--; + tmp[len] = 0; + } + + if (len == 0) { + ERROR("rrdtool plugin: Invalid \"DataDir\" option."); + sfree(tmp); + return 1; + } + + if (datadir != NULL) { + sfree(datadir); + } + + datadir = tmp; + } else if (strcasecmp("StepSize", key) == 0) { + unsigned long temp = strtoul(value, NULL, 0); + if (temp > 0) + rrdcreate_config.stepsize = temp; + } else if (strcasecmp("HeartBeat", key) == 0) { + int temp = atoi(value); + if (temp > 0) + rrdcreate_config.heartbeat = temp; + } else if (strcasecmp("CreateFilesAsync", key) == 0) { + if (IS_TRUE(value)) + rrdcreate_config.async = 1; + else + rrdcreate_config.async = 0; + } else if (strcasecmp("RRARows", key) == 0) { + int tmp = atoi(value); + if (tmp <= 0) { + fprintf(stderr, "rrdtool: `RRARows' must " + "be greater than 0.\n"); + ERROR("rrdtool: `RRARows' must " + "be greater than 0.\n"); + return 1; + } + rrdcreate_config.rrarows = tmp; + } else if (strcasecmp("RRATimespan", key) == 0) { + char *saveptr = NULL; + char *dummy; + char *ptr; + char *value_copy; + int *tmp_alloc; + + value_copy = strdup(value); + if (value_copy == NULL) + return 1; + + dummy = value_copy; + while ((ptr = strtok_r(dummy, ", \t", &saveptr)) != NULL) { + dummy = NULL; + + tmp_alloc = realloc(rrdcreate_config.timespans, + sizeof(int) * (rrdcreate_config.timespans_num + 1)); + if (tmp_alloc == NULL) { + fprintf(stderr, "rrdtool: realloc failed.\n"); + ERROR("rrdtool: realloc failed.\n"); + free(value_copy); + return 1; + } + rrdcreate_config.timespans = tmp_alloc; + rrdcreate_config.timespans[rrdcreate_config.timespans_num] = atoi(ptr); + if (rrdcreate_config.timespans[rrdcreate_config.timespans_num] != 0) + rrdcreate_config.timespans_num++; + } /* while (strtok_r) */ + + qsort(/* base = */ rrdcreate_config.timespans, + /* nmemb = */ rrdcreate_config.timespans_num, + /* size = */ sizeof(rrdcreate_config.timespans[0]), + /* compar = */ rrd_compare_numeric); + + free(value_copy); + } else if (strcasecmp("XFF", key) == 0) { + double tmp = atof(value); + if ((tmp < 0.0) || (tmp >= 1.0)) { + fprintf(stderr, "rrdtool: `XFF' must " + "be in the range 0 to 1 (exclusive)."); + ERROR("rrdtool: `XFF' must " + "be in the range 0 to 1 (exclusive)."); + return 1; + } + rrdcreate_config.xff = tmp; + } else if (strcasecmp("WritesPerSecond", key) == 0) { + double wps = atof(value); + + if (wps < 0.0) { + fprintf(stderr, "rrdtool: `WritesPerSecond' must be " + "greater than or equal to zero."); + return 1; + } else if (wps == 0.0) { + write_rate = 0.0; + } else { + write_rate = 1.0 / wps; + } + } else if (strcasecmp("RandomTimeout", key) == 0) { + double tmp; + + tmp = atof(value); + if (tmp < 0.0) { + fprintf(stderr, "rrdtool: `RandomTimeout' must " + "be greater than or equal to zero.\n"); + ERROR("rrdtool: `RandomTimeout' must " + "be greater then or equal to zero."); + } else { + random_timeout = DOUBLE_TO_CDTIME_T(tmp); + } + } else { + return -1; + } + return 0; } /* int rrd_config */ -static int rrd_shutdown (void) -{ - pthread_mutex_lock (&cache_lock); - rrd_cache_flush (0); - pthread_mutex_unlock (&cache_lock); - - pthread_mutex_lock (&queue_lock); - do_shutdown = 1; - pthread_cond_signal (&queue_cond); - pthread_mutex_unlock (&queue_lock); - - if ((queue_thread_running != 0) - && ((queue_head != NULL) || (flushq_head != NULL))) - { - INFO ("rrdtool plugin: Shutting down the queue thread. " - "This may take a while."); - } - else if (queue_thread_running != 0) - { - INFO ("rrdtool plugin: Shutting down the queue thread."); - } - - /* Wait for all the values to be written to disk before returning. */ - if (queue_thread_running != 0) - { - pthread_join (queue_thread, NULL); - memset (&queue_thread, 0, sizeof (queue_thread)); - queue_thread_running = 0; - DEBUG ("rrdtool plugin: queue_thread exited."); - } - - rrd_cache_destroy (); - - return (0); +static int rrd_shutdown(void) { + pthread_mutex_lock(&cache_lock); + rrd_cache_flush(0); + pthread_mutex_unlock(&cache_lock); + + pthread_mutex_lock(&queue_lock); + do_shutdown = 1; + pthread_cond_signal(&queue_cond); + pthread_mutex_unlock(&queue_lock); + + if ((queue_thread_running != 0) && + ((queue_head != NULL) || (flushq_head != NULL))) { + INFO("rrdtool plugin: Shutting down the queue thread. " + "This may take a while."); + } else if (queue_thread_running != 0) { + INFO("rrdtool plugin: Shutting down the queue thread."); + } + + /* Wait for all the values to be written to disk before returning. */ + if (queue_thread_running != 0) { + pthread_join(queue_thread, NULL); + memset(&queue_thread, 0, sizeof(queue_thread)); + queue_thread_running = 0; + DEBUG("rrdtool plugin: queue_thread exited."); + } + + rrd_cache_destroy(); + + return 0; } /* int rrd_shutdown */ -static int rrd_init (void) -{ - static int init_once = 0; - int status; - - if (init_once != 0) - return (0); - init_once = 1; - - if (rrdcreate_config.heartbeat <= 0) - rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize; - - /* Set the cache up */ - pthread_mutex_lock (&cache_lock); - - cache = c_avl_create ((int (*) (const void *, const void *)) strcmp); - if (cache == NULL) - { - pthread_mutex_unlock (&cache_lock); - ERROR ("rrdtool plugin: c_avl_create failed."); - return (-1); - } - - cache_flush_last = cdtime (); - if (cache_timeout == 0) - { - cache_flush_timeout = 0; - } - else if (cache_flush_timeout < cache_timeout) - cache_flush_timeout = 10 * cache_timeout; - - pthread_mutex_unlock (&cache_lock); - - status = plugin_thread_create (&queue_thread, /* attr = */ NULL, - rrd_queue_thread, /* args = */ NULL); - if (status != 0) - { - ERROR ("rrdtool plugin: Cannot create queue-thread."); - return (-1); - } - queue_thread_running = 1; - - DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %lu;" - " heartbeat = %i; rrarows = %i; xff = %lf;", - (datadir == NULL) ? "(null)" : datadir, - rrdcreate_config.stepsize, - rrdcreate_config.heartbeat, - rrdcreate_config.rrarows, - rrdcreate_config.xff); - - return (0); +static int rrd_init(void) { + static int init_once = 0; + + if (init_once != 0) + return 0; + init_once = 1; + + if (rrdcreate_config.heartbeat <= 0) + rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize; + + /* Set the cache up */ + pthread_mutex_lock(&cache_lock); + + cache = c_avl_create((int (*)(const void *, const void *))strcmp); + if (cache == NULL) { + pthread_mutex_unlock(&cache_lock); + ERROR("rrdtool plugin: c_avl_create failed."); + return -1; + } + + cache_flush_last = cdtime(); + if (cache_timeout == 0) { + random_timeout = 0; + cache_flush_timeout = 0; + } else if (cache_flush_timeout < cache_timeout) { + INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout " + "%.3f\". Adjusting \"CacheFlush\" to %.3f seconds.", + CDTIME_T_TO_DOUBLE(cache_flush_timeout), + CDTIME_T_TO_DOUBLE(cache_timeout), + CDTIME_T_TO_DOUBLE(cache_timeout * 10)); + cache_flush_timeout = 10 * cache_timeout; + } + + /* Assure that "cache_timeout + random_variation" is never negative. */ + if (random_timeout > cache_timeout) { + INFO("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.", + CDTIME_T_TO_DOUBLE(cache_timeout)); + random_timeout = cache_timeout; + } + + pthread_mutex_unlock(&cache_lock); + + int status = + plugin_thread_create(&queue_thread, /* attr = */ NULL, rrd_queue_thread, + /* args = */ NULL, "rrdtool queue"); + if (status != 0) { + ERROR("rrdtool plugin: Cannot create queue-thread."); + return -1; + } + queue_thread_running = 1; + + DEBUG("rrdtool plugin: rrd_init: datadir = %s; stepsize = %lu;" + " heartbeat = %i; rrarows = %i; xff = %lf;", + (datadir == NULL) ? "(null)" : datadir, rrdcreate_config.stepsize, + rrdcreate_config.heartbeat, rrdcreate_config.rrarows, + rrdcreate_config.xff); + + return 0; } /* int rrd_init */ -void module_register (void) -{ - plugin_register_config ("rrdtool", rrd_config, - config_keys, config_keys_num); - plugin_register_init ("rrdtool", rrd_init); - plugin_register_write ("rrdtool", rrd_write, /* user_data = */ NULL); - plugin_register_flush ("rrdtool", rrd_flush, /* user_data = */ NULL); - plugin_register_shutdown ("rrdtool", rrd_shutdown); +void module_register(void) { + plugin_register_config("rrdtool", rrd_config, config_keys, config_keys_num); + plugin_register_init("rrdtool", rrd_init); + plugin_register_write("rrdtool", rrd_write, /* user_data = */ NULL); + plugin_register_flush("rrdtool", rrd_flush, /* user_data = */ NULL); + plugin_register_shutdown("rrdtool", rrd_shutdown); }