Beautifying many debug messages..
[collectd.git] / src / rrdtool.c
index 3bb8e07..8ad0106 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/rrdtool.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  *
  * 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
 #include "common.h"
 #include "utils_avltree.h"
 
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
 /*
  * Private types
  */
@@ -32,6 +36,7 @@ struct rrd_cache_s
        int    values_num;
        char **values;
        time_t first_value;
+       time_t last_value;
 };
 typedef struct rrd_cache_s rrd_cache_t;
 
@@ -48,6 +53,9 @@ static int rra_timespans[] =
 };
 static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
 
+static int *rra_timespans_custom = NULL;
+static int rra_timespans_custom_num = 0;
+
 static char *rra_types[] =
 {
        "AVERAGE",
@@ -64,6 +72,7 @@ static const char *config_keys[] =
        "StepSize",
        "HeartBeat",
        "RRARows",
+       "RRATimespan",
        "XFF"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
@@ -78,6 +87,7 @@ static int         cache_timeout = 0;
 static int         cache_flush_timeout = 0;
 static time_t      cache_flush_last;
 static avl_tree_t *cache = NULL;
+static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /* * * * * * * * * *
  * WARNING:  Magic *
@@ -87,7 +97,10 @@ static int rra_get (char ***ret)
        static char **rra_def = NULL;
        static int rra_num = 0;
 
-       int rra_max = rra_timespans_num * rra_types_num;
+       int *rts;
+       int  rts_num;
+
+       int rra_max;
 
        int span;
 
@@ -103,6 +116,20 @@ static int rra_get (char ***ret)
                return (rra_num);
        }
 
+       /* Use the configured timespans or fall back to the built-in defaults */
+       if (rra_timespans_custom_num != 0)
+       {
+               rts = rra_timespans_custom;
+               rts_num = rra_timespans_custom_num;
+       }
+       else
+       {
+               rts = rra_timespans;
+               rts_num = rra_timespans_num;
+       }
+
+       rra_max = rts_num * rra_types_num;
+
        if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
                return (-1);
        memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
@@ -114,9 +141,9 @@ static int rra_get (char ***ret)
        }
 
        cdp_len = 0;
-       for (i = 0; i < rra_timespans_num; i++)
+       for (i = 0; i < rts_num; i++)
        {
-               span = rra_timespans[i];
+               span = rts[i];
 
                if ((span / stepsize) < rrarows)
                        continue;
@@ -256,7 +283,7 @@ static int ds_get (char ***ret, const data_set_t *ds)
        return (ds_num);
 }
 
-static int rrd_create_file (char *filename, const data_set_t *ds)
+static int rrd_create_file (char *filename, const data_set_t *ds, const value_list_t *vl)
 {
        char **argv;
        int argc;
@@ -266,6 +293,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
        int ds_num;
        int i, j;
        char stepsize_str[16];
+       char begin_str[16];
        int status = 0;
 
        if (check_create_dir (filename))
@@ -283,7 +311,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
                return (-1);
        }
 
-       argc = ds_num + rra_num + 4;
+       argc = ds_num + rra_num + 6;
 
        if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
        {
@@ -301,12 +329,23 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
                return (-1);
        }
 
+       assert (vl->time > 10);
+       status = snprintf (begin_str, sizeof (begin_str),
+                       "%llu", (unsigned long long) (vl->time - 10));
+       if ((status < 1) || (status >= sizeof (begin_str)))
+       {
+               ERROR ("rrdtool plugin: snprintf failed.");
+               return (-1);
+       }
+
        argv[0] = "create";
        argv[1] = filename;
-       argv[2] = "-s";
-       argv[3] = stepsize_str;
+       argv[2] = "-b";
+       argv[3] = begin_str;
+       argv[4] = "-s";
+       argv[5] = stepsize_str;
 
-       j = 4;
+       j = 6;
        for (i = 0; i < ds_num; i++)
                argv[j++] = ds_def[i];
        for (i = 0; i < rra_num; i++)
@@ -334,7 +373,7 @@ static int value_list_to_string (char *buffer, int buffer_len,
        int status;
        int i;
 
-       memset (buffer, '\0', sizeof (buffer_len));
+       memset (buffer, '\0', buffer_len);
 
        status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
        if ((status < 1) || (status >= buffer_len))
@@ -408,7 +447,7 @@ static int value_list_to_filename (char *buffer, int buffer_len,
 } /* int value_list_to_filename */
 
 static rrd_cache_t *rrd_cache_insert (const char *filename,
-               const char *value)
+               const char *value, time_t value_time)
 {
        rrd_cache_t *rc = NULL;
        int new_rc = 0;
@@ -424,9 +463,18 @@ static rrd_cache_t *rrd_cache_insert (const char *filename,
                rc->values_num = 0;
                rc->values = NULL;
                rc->first_value = 0;
+               rc->last_value = 0;
                new_rc = 1;
        }
 
+       if (rc->last_value >= value_time)
+       {
+               WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
+                               (unsigned int) rc->last_value,
+                               (unsigned int) value_time);
+               return (NULL);
+       }
+
        rc->values = (char **) realloc ((void *) rc->values,
                        (rc->values_num + 1) * sizeof (char *));
        if (rc->values == NULL)
@@ -449,7 +497,8 @@ static rrd_cache_t *rrd_cache_insert (const char *filename,
                rc->values_num++;
 
        if (rc->values_num == 1)
-               rc->first_value = time (NULL);
+               rc->first_value = value_time;
+       rc->last_value = value_time;
 
        /* Insert if this is the first value */
        if ((cache != NULL) && (new_rc == 1))
@@ -470,7 +519,8 @@ static rrd_cache_t *rrd_cache_insert (const char *filename,
                avl_insert (cache, cache_key, rc);
        }
 
-       DEBUG ("rrd_cache_insert (%s, %s) = %p", filename, value, (void *) rc);
+       DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value,
+                       (unsigned int) value_time, (void *) rc);
 
        return (rc);
 } /* rrd_cache_t *rrd_cache_insert */
@@ -485,6 +535,9 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
 
        int i;
 
+       if (rc->values_num < 1)
+               return (0);
+
        argc = rc->values_num + 2;
        argv = (char **) malloc ((argc + 1) * sizeof (char *));
        if (argv == NULL)
@@ -507,10 +560,15 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
        optind = 0; /* bug in librrd? */
        rrd_clear_error ();
        status = rrd_update (argc, argv);
+       if (status != 0)
+       {
+               WARNING ("rrd_update failed: %s: %s",
+                               filename, rrd_get_error ());
+               status = -1;
+       }
 
        free (argv);
        free (fn);
-
        /* Free the value list of `rc' */
        for (i = 0; i < rc->values_num; i++)
                free (rc->values[i]);
@@ -518,14 +576,7 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
        rc->values = NULL;
        rc->values_num = 0;
 
-       if (status != 0)
-       {
-               WARNING ("rrd_update failed: %s: %s",
-                               filename, rrd_get_error ());
-               return (-1);
-       }
-
-       return (0);
+       return (status);
 } /* int rrd_write_cache_entry */
 
 static void rrd_cache_flush (int timeout)
@@ -543,7 +594,7 @@ static void rrd_cache_flush (int timeout)
        if (cache == NULL)
                return;
 
-       DEBUG ("Flushing cache, timeout = %i", timeout);
+       DEBUG ("rrdtool plugin: Flushing cache, timeout = %i", timeout);
 
        now = time (NULL);
 
@@ -576,7 +627,7 @@ static void rrd_cache_flush (int timeout)
        {
                if (avl_remove (cache, keys[i], (void *) &key, (void *) &rc) != 0)
                {
-                       DEBUG ("avl_remove (%s) failed.", keys[i]);
+                       DEBUG ("rrdtool plugin: avl_remove (%s) failed.", keys[i]);
                        continue;
                }
 
@@ -588,7 +639,6 @@ static void rrd_cache_flush (int timeout)
        } /* for (i = 0..keys_num) */
 
        free (keys);
-       DEBUG ("Flushed %i value(s)", keys_num);
 
        cache_flush_last = now;
 } /* void rrd_cache_flush */
@@ -611,7 +661,7 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
        {
                if (errno == ENOENT)
                {
-                       if (rrd_create_file (filename, ds))
+                       if (rrd_create_file (filename, ds, vl))
                                return (-1);
                }
                else
@@ -630,15 +680,20 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
                return (-1);
        }
 
-       rc = rrd_cache_insert (filename, values);
+       pthread_mutex_lock (&cache_lock);
+       rc = rrd_cache_insert (filename, values, vl->time);
        if (rc == NULL)
+       {
+               pthread_mutex_unlock (&cache_lock);
                return (-1);
+       }
 
        if (cache == NULL)
        {
                rrd_write_cache_entry (filename, rc);
                /* rc's value-list is free's by `rrd_write_cache_entry' */
                sfree (rc);
+               pthread_mutex_unlock (&cache_lock);
                return (0);
        }
 
@@ -654,6 +709,7 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
        if ((now - cache_flush_last) >= cache_flush_timeout)
                rrd_cache_flush (cache_flush_timeout);
 
+       pthread_mutex_unlock (&cache_lock);
        return (0);
 } /* int rrd_write */
 
@@ -734,6 +790,38 @@ static int rrd_config (const char *key, const char *value)
                }
                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 (rra_timespans_custom,
+                                       sizeof (int) * (rra_timespans_custom_num + 1));
+                       if (tmp_alloc == NULL)
+                       {
+                               fprintf (stderr, "rrdtool: realloc failed.\n");
+                               free (value_copy);
+                               return (1);
+                       }
+                       rra_timespans_custom = tmp_alloc;
+                       rra_timespans_custom[rra_timespans_custom_num] = atoi (ptr);
+                       if (rra_timespans_custom[rra_timespans_custom_num] != 0)
+                               rra_timespans_custom_num++;
+               } /* while (strtok_r) */
+               free (value_copy);
+       }
        else if (strcasecmp ("XFF", key) == 0)
        {
                double tmp = atof (value);
@@ -754,10 +842,12 @@ static int rrd_config (const char *key, const char *value)
 
 static int rrd_shutdown (void)
 {
+       pthread_mutex_lock (&cache_lock);
        rrd_cache_flush (-1);
        if (cache != NULL)
                avl_destroy (cache);
        cache = NULL;
+       pthread_mutex_unlock (&cache_lock);
 
        return (0);
 } /* int rrd_shutdown */
@@ -778,6 +868,7 @@ static int rrd_init (void)
                                "smaller than your `interval'. This will "
                                "create needlessly big RRD-files.");
 
+       pthread_mutex_lock (&cache_lock);
        if (cache_timeout < 2)
        {
                cache_timeout = 0;
@@ -792,8 +883,10 @@ static int rrd_init (void)
                cache_flush_last = time (NULL);
                plugin_register_shutdown ("rrdtool", rrd_shutdown);
        }
+       pthread_mutex_unlock (&cache_lock);
 
-       DEBUG ("datadir = %s; stepsize = %i; heartbeat = %i; rrarows = %i; xff = %lf;",
+       DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
+                       " heartbeat = %i; rrarows = %i; xff = %lf;",
                        (datadir == NULL) ? "(null)" : datadir,
                        stepsize, heartbeat, rrarows, xff);