cpu plugin: Collectd CPU `steal time' as reported by new Linux kernels.
[collectd.git] / src / rrdtool.c
index f19f269..b221341 100644 (file)
 #include "plugin.h"
 #include "common.h"
 #include "utils_avltree.h"
-#include "utils_debug.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
 
 /*
  * Private types
@@ -79,6 +82,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 *
@@ -140,7 +144,7 @@ static int rra_get (char ***ret)
                                                rra_types[j], xff,
                                                cdp_len, cdp_num) >= sizeof (buffer))
                        {
-                               syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
+                               ERROR ("rra_get: Buffer would have been truncated.");
                                continue;
                        }
 
@@ -149,9 +153,9 @@ static int rra_get (char ***ret)
        }
 
 #if COLLECT_DEBUG
-       DBG ("rra_num = %i", rra_num);
+       DEBUG ("rra_num = %i", rra_num);
        for (i = 0; i < rra_num; i++)
-               DBG ("  %s", rra_def[i]);
+               DEBUG ("  %s", rra_def[i]);
 #endif
 
        *ret = rra_def;
@@ -177,13 +181,14 @@ static int ds_get (char ***ret, const data_set_t *ds)
        char max[32];
        char buffer[128];
 
-       DBG ("ds->ds_num = %i", ds->ds_num);
+       DEBUG ("ds->ds_num = %i", ds->ds_num);
 
        ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
        if (ds_def == NULL)
        {
-               syslog (LOG_ERR, "rrdtool plugin: malloc failed: %s",
-                               strerror (errno));
+               char errbuf[1024];
+               ERROR ("rrdtool plugin: malloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
        memset (ds_def, '\0', ds->ds_num * sizeof (char *));
@@ -202,7 +207,7 @@ static int ds_get (char ***ret, const data_set_t *ds)
                        type = "GAUGE";
                else
                {
-                       syslog (LOG_ERR, "rrdtool plugin: Unknown DS type: %i",
+                       ERROR ("rrdtool plugin: Unknown DS type: %i",
                                        d->type);
                        break;
                }
@@ -240,9 +245,9 @@ static int ds_get (char ***ret, const data_set_t *ds)
 #if COLLECT_DEBUG
 {
        int i;
-       DBG ("ds_num = %i", ds_num);
+       DEBUG ("ds_num = %i", ds_num);
        for (i = 0; i < ds_num; i++)
-               DBG ("  %s", ds_def[i]);
+               DEBUG ("  %s", ds_def[i]);
 }
 #endif
 
@@ -273,13 +278,13 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
 
        if ((rra_num = rra_get (&rra_def)) < 1)
        {
-               syslog (LOG_ERR, "rrd_create_file failed: Could not calculate RRAs");
+               ERROR ("rrd_create_file failed: Could not calculate RRAs");
                return (-1);
        }
 
        if ((ds_num = ds_get (&ds_def, ds)) < 1)
        {
-               syslog (LOG_ERR, "rrd_create_file failed: Could not calculate DSes");
+               ERROR ("rrd_create_file failed: Could not calculate DSes");
                return (-1);
        }
 
@@ -287,7 +292,9 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
 
        if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
        {
-               syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
+               char errbuf[1024];
+               ERROR ("rrd_create failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
 
@@ -295,7 +302,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
                        "%i", stepsize);
        if ((status < 1) || (status >= sizeof (stepsize_str)))
        {
-               syslog (LOG_ERR, "rrdtool plugin: snprintf failed.");
+               ERROR ("rrdtool plugin: snprintf failed.");
                return (-1);
        }
 
@@ -315,7 +322,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds)
        rrd_clear_error ();
        if (rrd_create (argc, argv) == -1)
        {
-               syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
+               ERROR ("rrd_create failed: %s: %s", filename, rrd_get_error ());
                status = -1;
        }
 
@@ -429,8 +436,9 @@ static rrd_cache_t *rrd_cache_insert (const char *filename,
                        (rc->values_num + 1) * sizeof (char *));
        if (rc->values == NULL)
        {
-               syslog (LOG_ERR, "rrdtool plugin: realloc failed: %s",
-                               strerror (errno));
+               char errbuf[1024];
+               ERROR ("rrdtool plugin: realloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                if (cache != NULL)
                {
                        void *cache_key = NULL;
@@ -455,8 +463,9 @@ static rrd_cache_t *rrd_cache_insert (const char *filename,
 
                if (cache_key == NULL)
                {
-                       syslog (LOG_ERR, "rrdtool plugin: strdup failed: %s",
-                                       strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("rrdtool plugin: strdup failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        sfree (rc->values[0]);
                        sfree (rc->values);
                        sfree (rc);
@@ -466,7 +475,7 @@ static rrd_cache_t *rrd_cache_insert (const char *filename,
                avl_insert (cache, cache_key, rc);
        }
 
-       DBG ("rrd_cache_insert (%s, %s) = %p", filename, value, (void *) rc);
+       DEBUG ("rrd_cache_insert (%s, %s) = %p", filename, value, (void *) rc);
 
        return (rc);
 } /* rrd_cache_t *rrd_cache_insert */
@@ -481,6 +490,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)
@@ -498,15 +510,20 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
        memcpy (argv + 2, rc->values, rc->values_num * sizeof (char *));
        argv[argc] = NULL;
 
-       DBG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
+       DEBUG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
 
        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]);
@@ -514,14 +531,7 @@ static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
        rc->values = NULL;
        rc->values_num = 0;
 
-       if (status != 0)
-       {
-               syslog (LOG_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)
@@ -539,7 +549,7 @@ static void rrd_cache_flush (int timeout)
        if (cache == NULL)
                return;
 
-       DBG ("Flushing cache, timeout = %i", timeout);
+       DEBUG ("Flushing cache, timeout = %i", timeout);
 
        now = time (NULL);
 
@@ -547,17 +557,18 @@ static void rrd_cache_flush (int timeout)
        iter = avl_get_iterator (cache);
        while (avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0)
        {
-               DBG ("key = %s; age = %i;", key, now - rc->first_value);
+               DEBUG ("key = %s; age = %i;", key, now - rc->first_value);
                if ((now - rc->first_value) >= timeout)
                {
                        keys = (char **) realloc ((void *) keys,
                                        (keys_num + 1) * sizeof (char *));
                        if (keys == NULL)
                        {
-                               DBG ("realloc failed: %s", strerror (errno));
-                               syslog (LOG_ERR, "rrdtool plugin: "
+                               char errbuf[1024];
+                               ERROR ("rrdtool plugin: "
                                                "realloc failed: %s",
-                                               strerror (errno));
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                avl_iterator_destroy (iter);
                                return;
                        }
@@ -571,7 +582,7 @@ static void rrd_cache_flush (int timeout)
        {
                if (avl_remove (cache, keys[i], (void *) &key, (void *) &rc) != 0)
                {
-                       DBG ("avl_remove (%s) failed.", keys[i]);
+                       DEBUG ("avl_remove (%s) failed.", keys[i]);
                        continue;
                }
 
@@ -583,7 +594,7 @@ static void rrd_cache_flush (int timeout)
        } /* for (i = 0..keys_num) */
 
        free (keys);
-       DBG ("Flushed %i value(s)", keys_num);
+       DEBUG ("Flushed %i value(s)", keys_num);
 
        cache_flush_last = now;
 } /* void rrd_cache_flush */
@@ -611,33 +622,40 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
                }
                else
                {
-                       syslog (LOG_ERR, "stat(%s) failed: %s",
-                                       filename, strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("stat(%s) failed: %s", filename,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
        }
        else if (!S_ISREG (statbuf.st_mode))
        {
-               syslog (LOG_ERR, "stat(%s): Not a regular file!",
+               ERROR ("stat(%s): Not a regular file!",
                                filename);
                return (-1);
        }
 
+       pthread_mutex_lock (&cache_lock);
        rc = rrd_cache_insert (filename, values);
        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);
        }
 
        now = time (NULL);
 
-       DBG ("age (%s) = %i", filename, now - rc->first_value);
+       DEBUG ("age (%s) = %i", filename, now - rc->first_value);
 
        /* `rc' is not free'd here, because we'll likely reuse it. If not, then
         * the next flush will remove this entry.  */
@@ -647,6 +665,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 */
 
@@ -747,10 +766,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 */
@@ -763,14 +784,15 @@ static int rrd_init (void)
                heartbeat = 2 * interval_g;
 
        if (heartbeat < interval_g)
-               syslog (LOG_WARNING, "rrdtool plugin: Your `heartbeat' is "
+               WARNING ("rrdtool plugin: Your `heartbeat' is "
                                "smaller than your `interval'. This will "
                                "likely cause problems.");
        else if (stepsize < interval_g)
-               syslog (LOG_WARNING, "rrdtool plugin: Your `stepsize' is "
+               WARNING ("rrdtool plugin: Your `stepsize' is "
                                "smaller than your `interval'. This will "
                                "create needlessly big RRD-files.");
 
+       pthread_mutex_lock (&cache_lock);
        if (cache_timeout < 2)
        {
                cache_timeout = 0;
@@ -785,15 +807,17 @@ static int rrd_init (void)
                cache_flush_last = time (NULL);
                plugin_register_shutdown ("rrdtool", rrd_shutdown);
        }
+       pthread_mutex_unlock (&cache_lock);
 
-       DBG ("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);
 
        return (0);
 } /* int rrd_init */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
        plugin_register_config ("rrdtool", rrd_config,
                        config_keys, config_keys_num);