diff --git a/src/rrdtool.c b/src/rrdtool.c
index 2787944330b28959ec81d8c25a9e9d90d9fe6f23..2c80762ecb905454f843620fd86cf3cd449ba8f7 100644 (file)
--- a/src/rrdtool.c
+++ b/src/rrdtool.c
/**
* collectd - src/rrdtool.c
- * Copyright (C) 2006-2008 Florian octo Forster
+ * Copyright (C) 2006-2013 Florian octo Forster
+ * Copyright (C) 2008-2008 Sebastian Harl
+ * Copyright (C) 2009 Mariusz Gronczewski
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
+ * Sebastian Harl <sh at tokkee.org>
+ * Mariusz Gronczewski <xani666 at gmail.com>
**/
#include "collectd.h"
#include "plugin.h"
#include "common.h"
#include "utils_avltree.h"
+#include "utils_random.h"
#include "utils_rrdcreate.h"
#include <rrd.h>
*/
struct rrd_cache_s
{
- int values_num;
- char **values;
- time_t first_value;
- time_t last_value;
+ int values_num;
+ char **values;
+ cdtime_t first_value;
+ cdtime_t last_value;
+ int64_t random_variation;
enum
{
FLAG_NONE = 0x00,
{
"CacheTimeout",
"CacheFlush",
+ "CreateFilesAsync",
"DataDir",
"StepSize",
"HeartBeat",
/* timespans_num = */ 0,
/* consolidation_functions = */ NULL,
- /* consolidation_functions_num = */ 0
+ /* consolidation_functions_num = */ 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 int cache_timeout = 0;
-static int cache_flush_timeout = 0;
-static int random_timeout = 1;
-static int random_timeout_mod = 1;
-static time_t cache_flush_last;
+static cdtime_t cache_timeout = 0;
+static cdtime_t cache_flush_timeout = 0;
+static cdtime_t random_timeout = TIME_T_TO_CDTIME_T (1);
+static cdtime_t cache_flush_last;
static c_avl_tree_t *cache = NULL;
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
if (status != 0)
{
WARNING ("rrdtool plugin: rrd_update_r failed: %s: %s",
- argv[1], rrd_get_error ());
+ filename, rrd_get_error ());
}
sfree (new_argv);
{
int offset;
int status;
+ time_t tt;
int i;
memset (buffer, '\0', buffer_len);
- status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ 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;
pthread_mutex_lock (&queue_lock);
/* Wait for values to arrive */
- while (true)
+ while (42)
{
struct timespec ts_wait;
&ts_wait);
if (status == ETIMEDOUT)
break;
- } /* while (true) */
+ } /* while (42) */
/* XXX: If you need to lock both, cache_lock and queue_lock, at
* the same time, ALWAYS lock `cache_lock' first! */
sfree (queue_entry);
} /* while (42) */
- pthread_mutex_lock (&cache_lock);
- c_avl_destroy (cache);
- cache = NULL;
- pthread_mutex_unlock (&cache_lock);
-
pthread_exit ((void *) 0);
return ((void *) 0);
} /* void *rrd_queue_thread */
return (0);
} /* int rrd_queue_dequeue */
-static void rrd_cache_flush (int timeout)
+/* XXX: You must hold "cache_lock" when calling this function! */
+static void rrd_cache_flush (cdtime_t timeout)
{
rrd_cache_t *rc;
- time_t now;
+ cdtime_t now;
char **keys = NULL;
int keys_num = 0;
c_avl_iterator_t *iter;
int i;
- DEBUG ("rrdtool plugin: Flushing cache, timeout = %i", timeout);
+ DEBUG ("rrdtool plugin: Flushing cache, timeout = %.3f",
+ CDTIME_T_TO_DOUBLE (timeout));
- now = time (NULL);
+ now = cdtime ();
+ timeout = TIME_T_TO_CDTIME_T (timeout);
/* Build a list of entries to be flushed */
iter = c_avl_get_iterator (cache);
{
if (rc->flags != FLAG_NONE)
continue;
- else if ((now - rc->first_value) < timeout)
+ /* timeout == 0 => flush everything */
+ else if ((timeout != 0)
+ && ((now - rc->first_value) < timeout))
continue;
else if (rc->values_num > 0)
{
cache_flush_last = now;
} /* void rrd_cache_flush */
-static int rrd_cache_flush_identifier (int timeout, const char *identifier)
+static int rrd_cache_flush_identifier (cdtime_t timeout,
+ const char *identifier)
{
rrd_cache_t *rc;
- time_t now;
+ cdtime_t now;
int status;
char key[2048];
return (0);
}
- now = time (NULL);
+ now = cdtime ();
if (datadir == NULL)
snprintf (key, sizeof (key), "%s.rrd",
return (status);
} /* int rrd_cache_flush_identifier */
+static int64_t rrd_get_random_variation (void)
+{
+ long min;
+ long max;
+
+ if (random_timeout <= 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;
+ }
+
+ max = (long) (random_timeout / 2);
+ min = max - ((long) random_timeout);
+
+ return ((int64_t) cdrand_range (min, max));
+} /* int64_t rrd_get_random_variation */
+
static int rrd_cache_insert (const char *filename,
- const char *value, time_t value_time)
+ const char *value, cdtime_t value_time)
{
rrd_cache_t *rc = NULL;
int new_rc = 0;
if (rc == NULL)
{
- rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+ rc = malloc (sizeof (*rc));
if (rc == NULL)
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;
}
if (rc->last_value >= value_time)
{
pthread_mutex_unlock (&cache_lock);
- WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
- (unsigned int) rc->last_value,
- (unsigned int) value_time);
+ DEBUG ("rrdtool plugin: (rc->last_value = %"PRIu64") "
+ ">= (value_time = %"PRIu64")",
+ rc->last_value, value_time);
return (-1);
}
}
DEBUG ("rrdtool plugin: rrd_cache_insert: file = %s; "
- "values_num = %i; age = %lu;",
+ "values_num = %i; age = %.3f;",
filename, rc->values_num,
- (unsigned long)(rc->last_value - rc->first_value));
+ CDTIME_T_TO_DOUBLE (rc->last_value - rc->first_value));
-
- if ((rc->last_value - rc->first_value) >= (cache_timeout + (random_timeout - (rand() % random_timeout_mod) ) ) )
+ 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! */
status = rrd_queue_enqueue (filename, &queue_head, &queue_tail);
if (status == 0)
rc->flags = FLAG_QUEUED;
+
+ rc->random_variation = rrd_get_random_variation ();
}
else
{
}
if ((cache_timeout > 0) &&
- ((time (NULL) - cache_flush_last) > cache_flush_timeout))
+ ((cdtime () - cache_flush_last) > cache_flush_timeout))
rrd_cache_flush (cache_flush_timeout);
pthread_mutex_unlock (&cache_lock);
return (0);
} /* int rrd_cache_insert */
+static int rrd_cache_destroy (void) /* {{{ */
+{
+ void *key = NULL;
+ void *value = NULL;
+
+ int non_empty = 0;
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (cache == NULL)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ return (0);
+ }
+
+ while (c_avl_pick (cache, &key, &value) == 0)
+ {
+ rrd_cache_t *rc;
+ int i;
+
+ sfree (key);
+ key = NULL;
+
+ rc = value;
+ value = NULL;
+
+ if (rc->values_num > 0)
+ non_empty++;
+
+ for (i = 0; i < rc->values_num; i++)
+ sfree (rc->values[i]);
+ sfree (rc->values);
+ sfree (rc);
+ }
+
+ 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.");
+ }
+
+ 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);
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;
ds, vl, &rrdcreate_config);
if (status != 0)
return (-1);
+ else if (rrdcreate_config.async)
+ return (0);
}
else
{
return (status);
} /* int rrd_write */
-static int rrd_flush (int timeout, const char *identifier,
- user_data_t __attribute__((unused)) *user_data)
+static int rrd_flush (cdtime_t timeout, const char *identifier,
+ __attribute__((unused)) user_data_t *user_data)
{
pthread_mutex_lock (&cache_lock);
{
if (strcasecmp ("CacheTimeout", key) == 0)
{
- int tmp = atoi (value);
+ double tmp = atof (value);
if (tmp < 0)
{
fprintf (stderr, "rrdtool: `CacheTimeout' must "
"be greater than 0.\n");
return (1);
}
- cache_timeout = tmp;
+ cache_timeout = DOUBLE_TO_CDTIME_T (tmp);
}
else if (strcasecmp ("CacheFlush", key) == 0)
{
}
else if (strcasecmp ("StepSize", key) == 0)
{
- int temp = atoi (value);
+ unsigned long temp = strtoul (value, NULL, 0);
if (temp > 0)
rrdcreate_config.stepsize = temp;
}
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);
}
else if (strcasecmp ("RandomTimeout", key) == 0)
{
- random_timeout = atoi (value);
- if( random_timeout < 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
{
- fprintf (stderr, "rrdtool: `RandomTimeout' must "
- "be greater than or equal to zero.\n");
- ERROR ("rrdtool: `RandomTimeout' must "
- "be greater then or equal to zero.\n");
+ random_timeout = DOUBLE_TO_CDTIME_T (tmp);
}
- else if (random_timeout==0) {random_timeout=1;}
- else {random_timeout_mod = random_timeout * 2;}
}
else
{
static int rrd_shutdown (void)
{
pthread_mutex_lock (&cache_lock);
- rrd_cache_flush (-1);
+ rrd_cache_flush (0);
pthread_mutex_unlock (&cache_lock);
pthread_mutex_lock (&queue_lock);
DEBUG ("rrdtool plugin: queue_thread exited.");
}
- /* TODO: Maybe it'd be a good idea to free the cache here.. */
+ rrd_cache_destroy ();
return (0);
} /* int rrd_shutdown */
return (0);
init_once = 1;
- if (rrdcreate_config.stepsize < 0)
- rrdcreate_config.stepsize = 0;
if (rrdcreate_config.heartbeat <= 0)
rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize;
- if ((rrdcreate_config.heartbeat > 0)
- && (rrdcreate_config.heartbeat < interval_g))
- WARNING ("rrdtool plugin: Your `heartbeat' is "
- "smaller than your `interval'. This will "
- "likely cause problems.");
- else if ((rrdcreate_config.stepsize > 0)
- && (rrdcreate_config.stepsize < interval_g))
- WARNING ("rrdtool plugin: Your `stepsize' is "
- "smaller than your `interval'. This will "
- "create needlessly big RRD-files.");
-
/* Set the cache up */
pthread_mutex_lock (&cache_lock);
return (-1);
}
- cache_flush_last = time (NULL);
- if (cache_timeout < 2)
+ cache_flush_last = cdtime ();
+ if (cache_timeout == 0)
{
- cache_timeout = 0;
cache_flush_timeout = 0;
}
else if (cache_flush_timeout < cache_timeout)
pthread_mutex_unlock (&cache_lock);
- status = pthread_create (&queue_thread, /* attr = */ NULL,
+ status = plugin_thread_create (&queue_thread, /* attr = */ NULL,
rrd_queue_thread, /* args = */ NULL);
if (status != 0)
{
}
queue_thread_running = 1;
- DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
+ DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %lu;"
" heartbeat = %i; rrarows = %i; xff = %lf;",
(datadir == NULL) ? "(null)" : datadir,
rrdcreate_config.stepsize,