rrdtool plugin: Degrade a less than helpful warning to a debug message.
[collectd.git] / src / rrdtool.c
index 780b2e5..4655b96 100644 (file)
@@ -1,6 +1,8 @@
 /**
  * collectd - src/rrdtool.c
  * Copyright (C) 2006-2008  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
@@ -17,6 +19,8 @@
  *
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
+ *   Sebastian Harl <sh at tokkee.org>
+ *   Mariusz Gronczewski <xani666 at gmail.com>
  **/
 
 #include "collectd.h"
@@ -40,6 +44,7 @@ struct rrd_cache_s
        char **values;
        time_t first_value;
        time_t last_value;
+       int random_variation;
        enum
        {
                FLAG_NONE   = 0x00,
@@ -76,7 +81,8 @@ static const char *config_keys[] =
        "RRARows",
        "RRATimespan",
        "XFF",
-       "WritesPerSecond"
+       "WritesPerSecond",
+       "RandomTimeout"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
@@ -103,6 +109,7 @@ static rrdcreate_config_t rrdcreate_config =
  * ALWAYS lock `cache_lock' first! */
 static int         cache_timeout = 0;
 static int         cache_flush_timeout = 0;
+static int         random_timeout = 1;
 static time_t      cache_flush_last;
 static c_avl_tree_t *cache = NULL;
 static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -204,15 +211,23 @@ static int value_list_to_string (char *buffer, int buffer_len,
        for (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_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
+               else if (ds->ds[i].type == DS_TYPE_GAUGE)
                        status = ssnprintf (buffer + offset, buffer_len - offset,
                                        ":%lf", 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);
@@ -417,11 +432,6 @@ static void *rrd_queue_thread (void __attribute__((unused)) *data)
                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 */
@@ -601,7 +611,7 @@ static int rrd_cache_flush_identifier (int timeout, const char *identifier)
   status = c_avl_get (cache, key, (void *) &rc);
   if (status != 0)
   {
-    WARNING ("rrdtool plugin: rrd_cache_flush_identifier: "
+    INFO ("rrdtool plugin: rrd_cache_flush_identifier: "
         "c_avl_get (%s) failed. Does that file really exist?",
         key);
     return (status);
@@ -661,6 +671,7 @@ static int rrd_cache_insert (const char *filename,
                rc->values = NULL;
                rc->first_value = 0;
                rc->last_value = 0;
+               rc->random_variation = 0;
                rc->flags = FLAG_NONE;
                new_rc = 1;
        }
@@ -668,7 +679,7 @@ static int rrd_cache_insert (const char *filename,
        if (rc->last_value >= value_time)
        {
                pthread_mutex_unlock (&cache_lock);
-               WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
+               DEBUG ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
                                (unsigned int) rc->last_value,
                                (unsigned int) value_time);
                return (-1);
@@ -731,7 +742,7 @@ static int rrd_cache_insert (const char *filename,
                        filename, rc->values_num,
                        (unsigned long)(rc->last_value - rc->first_value));
 
-       if ((rc->last_value - rc->first_value) >= cache_timeout)
+       if ((rc->last_value + rc->random_variation - rc->first_value) >= cache_timeout)
        {
                /* XXX: If you need to lock both, cache_lock and queue_lock, at
                 * the same time, ALWAYS lock `cache_lock' first! */
@@ -742,6 +753,18 @@ static int rrd_cache_insert (const char *filename,
                        status = rrd_queue_enqueue (filename, &queue_head, &queue_tail);
                        if (status == 0)
                                rc->flags = FLAG_QUEUED;
+
+                       /* Update the jitter value. Negative values are
+                        * slightly preferred. */
+                       if (random_timeout > 0)
+                       {
+                               rc->random_variation = (rand () % (2 * random_timeout))
+                                       - random_timeout;
+                       }
+                       else
+                       {
+                               rc->random_variation = 0;
+                       }
                }
                else
                {
@@ -758,6 +781,59 @@ static int rrd_cache_insert (const char *filename,
        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);
@@ -779,6 +855,9 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl,
        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;
@@ -980,6 +1059,23 @@ static int rrd_config (const char *key, const char *value)
                        write_rate = 1.0 / wps;
                }
        }
+       else if (strcasecmp ("RandomTimeout", key) == 0)
+        {
+               int tmp;
+
+               tmp = atoi (value);
+               if (tmp < 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 = tmp;
+               }
+       }
        else
        {
                return (-1);
@@ -1018,7 +1114,7 @@ static int rrd_shutdown (void)
                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 */