Merge branch 'collectd-4.7'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Mon, 17 Aug 2009 08:46:05 +0000 (10:46 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Mon, 17 Aug 2009 08:46:05 +0000 (10:46 +0200)
Conflicts:
src/network.c

ChangeLog
contrib/collection3/bin/graph.cgi
contrib/collection3/etc/collection.conf
contrib/fedora/init.d-collectd
src/collectd.conf.in
src/collectd.conf.pod
src/java.c
src/libvirt.c
src/meta_data.c
src/plugin.c
src/utils_cache.c

index d129000..1d6decb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -78,7 +78,7 @@
        * collectd: A programming error has been fixed in the notification
          code. The bug may result in an assertion failure.
        * memcached plugin: Portability fix for Solaris. Thanks to Amit Gupta
-         for reposting the bug.
+         for reporting the bug.
 
 2009-06-02, Version 4.6.3
        * Build system, various plugins: Many build fixes for FreeBSD,
index c096dc9..8a5bf85 100755 (executable)
@@ -3,6 +3,7 @@
 use strict;
 use warnings;
 use lib ('../lib');
+use utf8;
 
 use FindBin ('$RealBin');
 use Carp (qw(confess cluck));
index 492bfa2..f56d1ca 100644 (file)
@@ -441,7 +441,7 @@ GraphWidth 400
   DataSources value
   RRDTitle "Processes on {hostname}"
   RRDVerticalLabel "Processes"
-  RRDFormat "%5.1lf%s"
+  RRDFormat "%5.1lf"
   DSName running  Running
   DSName sleeping Sleeping
   DSName paging   Paging
@@ -505,8 +505,8 @@ GraphWidth 400
   DataSources value
   DSName value Temp
   RRDTitle "Temperature ({instance})"
-  RRDVerticalLabel "°Celsius"
-  RRDFormat "%4.1lf°C"
+  RRDVerticalLabel "°Celsius"
+  RRDFormat "%4.1lf°C"
 </Type>
 <Type users>
   DataSources users
@@ -532,4 +532,4 @@ GraphWidth 400
   RRDVerticalLabel "W"
   RRDFormat "%4.1lfW"
 </Type>
-# vim: set sw=2 sts=2 et syntax=apache fileencoding=latin-1 :
+# vim: set sw=2 sts=2 et syntax=apache fileencoding=utf-8 :
index 2bf877c..ea8662a 100644 (file)
@@ -54,7 +54,7 @@ case "$1" in
        start
        ;;
   condrestart)
-       [ -f /var/lock/subsys/$prog ] && restart || :
+       [ -f /var/lock/subsys/$prog ] && stop && start || :
        ;;
   *)
        echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
index 1ed9da6..003cf16 100644 (file)
@@ -304,7 +304,7 @@ FQDNLookup   true
 #  Port "7634"
 #
 #  #----------------------------------------------------------------#
-#  # `TranslateDevicename' enabled backwards compatibility behavior #
+#  # `TranslateDevicename' enables backwards compatibility behavior #
 #  # and is enabled by default. Setting this option to `false' is   #
 #  # highly recommended.                                            #
 #  #----------------------------------------------------------------#
index 6483755..4704237 100644 (file)
@@ -2785,7 +2785,7 @@ matching values will be ignored.
 
 =head2 Plugin C<rrdcached>
 
-The C<rrdcached> plugin uses the RRDTool accelerator daemon, L<rrdcached(1)>,
+The C<rrdcached> plugin uses the RRDtool accelerator daemon, L<rrdcached(1)>,
 to store values to RRD files in an efficient manner. The combination of the
 C<rrdcached> B<plugin> and the C<rrdcached> B<daemon> is very similar to the
 way the C<rrdtool> plugin works (see below). The added abstraction layer
@@ -2837,7 +2837,7 @@ expected. Default is B<true>.
 
 You can use the settings B<StepSize>, B<HeartBeat>, B<RRARows>, and B<XFF> to
 fine-tune your RRD-files. Please read L<rrdcreate(1)> if you encounter problems
-using these settings. If you don't want to dive into the depths of RRDTool, you
+using these settings. If you don't want to dive into the depths of RRDtool, you
 can safely ignore these settings.
 
 =over 4
index 03df2b7..e029a0b 100644 (file)
@@ -93,6 +93,8 @@ static cjni_callback_info_t *java_callbacks      = NULL;
 static size_t                java_callbacks_num  = 0;
 static pthread_mutex_t       java_callbacks_lock = PTHREAD_MUTEX_INITIALIZER;
 
+static oconfig_item_t       *config_block = NULL;
+
 /*
  * Prototypes
  *
@@ -2314,7 +2316,7 @@ static int cjni_config_plugin_block (oconfig_item_t *ci) /* {{{ */
   return (0);
 } /* }}} int cjni_config_plugin_block */
 
-static int cjni_config (oconfig_item_t *ci) /* {{{ */
+static int cjni_config_perform (oconfig_item_t *ci) /* {{{ */
 {
   int success;
   int errors;
@@ -2369,7 +2371,55 @@ static int cjni_config (oconfig_item_t *ci) /* {{{ */
   }
 
   return (0);
-} /* }}} int cjni_config */
+} /* }}} int cjni_config_perform */
+
+/* Copy the children of `ci' to the global `config_block' variable. */
+static int cjni_config_callback (oconfig_item_t *ci) /* {{{ */
+{
+  oconfig_item_t *ci_copy;
+  oconfig_item_t *tmp;
+
+  assert (ci != NULL);
+  if (ci->children_num == 0)
+    return (0); /* nothing to do */
+
+  ci_copy = oconfig_clone (ci);
+  if (ci_copy == NULL)
+  {
+    ERROR ("java plugin: oconfig_clone failed.");
+    return (-1);
+  }
+
+  if (config_block == NULL)
+  {
+    config_block = ci_copy;
+    return (0);
+  }
+
+  tmp = realloc (config_block->children,
+      (config_block->children_num + ci_copy->children_num) * sizeof (*tmp));
+  if (tmp == NULL)
+  {
+    ERROR ("java plugin: realloc failed.");
+    oconfig_free (ci_copy);
+    return (-1);
+  }
+  config_block->children = tmp;
+
+  /* Copy the pointers */
+  memcpy (config_block->children + config_block->children_num,
+      ci_copy->children,
+      ci_copy->children_num * sizeof (*ci_copy->children));
+
+  /* Delete the pointers from the copy, so `oconfig_free' can't free them. */
+  memset (ci_copy->children, 0,
+      ci_copy->children_num * sizeof (*ci_copy->children));
+  ci_copy->children_num = 0;
+
+  oconfig_free (ci_copy);
+
+  return (0);
+} /* }}} int cjni_config_callback */
 
 /* Free the data contained in the `user_data_t' pointer passed to `cjni_read'
  * and `cjni_write'. In particular, delete the global reference to the Java
@@ -3005,6 +3055,22 @@ static int cjni_init (void) /* {{{ */
 {
   JNIEnv *jvm_env;
 
+  if ((config_block == NULL) && (jvm == NULL))
+  {
+    ERROR ("java plugin: cjni_init: No configuration block for "
+        "the java plugin was found.");
+    return (-1);
+  }
+
+  if (config_block != NULL)
+  {
+    int status;
+
+    status = cjni_config_perform (config_block);
+    oconfig_free (config_block);
+    config_block = NULL;
+  }
+
   if (jvm == NULL)
   {
     ERROR ("java plugin: cjni_init: jvm == NULL");
@@ -3023,7 +3089,7 @@ static int cjni_init (void) /* {{{ */
 
 void module_register (void)
 {
-  plugin_register_complex_config ("java", cjni_config);
+  plugin_register_complex_config ("java", cjni_config_callback);
   plugin_register_init ("java", cjni_init);
   plugin_register_shutdown ("java", cjni_shutdown);
 } /* void module_register (void) */
index 5acff29..6f9e5f1 100644 (file)
@@ -24,6 +24,7 @@
 #include "plugin.h"
 #include "configfile.h"
 #include "utils_ignorelist.h"
+#include "utils_complain.h"
 
 #include <libvirt/libvirt.h>
 #include <libvirt/virterror.h>
@@ -49,6 +50,8 @@ static const char *config_keys[] = {
 
 /* Connection. */
 static virConnectPtr conn = 0;
+static char *conn_string = NULL;
+static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
 
 /* Seconds between list refreshes, 0 disables completely. */
 static int interval = 60;
@@ -153,15 +156,13 @@ lv_config (const char *key, const char *value)
         il_interface_devices = ignorelist_create (1);
 
     if (strcasecmp (key, "Connection") == 0) {
-        if (conn != 0) {
-            ERROR ("Connection may only be given once in config file");
-            return 1;
-        }
-        conn = virConnectOpenReadOnly (value);
-        if (!conn) {
-            VIRT_ERROR (NULL, "connection failed");
+        char *tmp = strdup (value);
+        if (tmp == NULL) {
+            ERROR ("libvirt plugin: Connection strdup failed.");
             return 1;
         }
+        sfree (conn_string);
+        conn_string = tmp;
         return 0;
     }
 
@@ -253,19 +254,29 @@ lv_read (void)
     int i;
 
     if (conn == NULL) {
-        ERROR ("libvirt plugin: Not connected. Use Connection in "
-                "config file to supply connection URI.  For more information "
-                "see <http://libvirt.org/uri.html>");
-        return -1;
+        /* `conn_string == NULL' is acceptable. */
+        conn = virConnectOpenReadOnly (conn_string);
+        if (conn == NULL) {
+            c_complain (LOG_ERR, &conn_complain,
+                    "libvirt plugin: Unable to connect: "
+                    "virConnectOpenReadOnly failed.");
+            return -1;
+        }
     }
+    c_release (LOG_NOTICE, &conn_complain,
+            "libvirt plugin: Connection established.");
 
     time (&t);
 
     /* Need to refresh domain or device lists? */
     if ((last_refresh == (time_t) 0) ||
             ((interval > 0) && ((last_refresh + interval) <= t))) {
-        if (refresh_lists () != 0)
+        if (refresh_lists () != 0) {
+            if (conn != NULL)
+                virConnectClose (conn);
+            conn = NULL;
             return -1;
+        }
         last_refresh = t;
     }
 
index d7fe2eb..3a3f5e7 100644 (file)
@@ -409,7 +409,7 @@ int meta_data_get_string (meta_data_t *md, /* {{{ */
     return (-ENOENT);
   }
 
-  if (e->type != MD_TYPE_SIGNED_INT)
+  if (e->type != MD_TYPE_STRING)
   {
     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
     pthread_mutex_unlock (&md->lock);
index a5ae97b..b150cf6 100644 (file)
@@ -51,6 +51,7 @@ typedef struct callback_func_s callback_func_t;
 
 #define RF_SIMPLE  0
 #define RF_COMPLEX 1
+#define RF_REMOVE  65535
 struct read_func_s
 {
        /* `read_func_t' "inherits" from `callback_func_t'.
@@ -84,6 +85,7 @@ static c_avl_tree_t *data_sets;
 static char *plugindir = NULL;
 
 static c_heap_t       *read_heap = NULL;
+static llist_t        *read_list;
 static int             read_loop = 1;
 static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t  read_cond = PTHREAD_COND_INITIALIZER;
@@ -307,6 +309,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                read_func_t *rf;
                struct timeval now;
                int status;
+               int rf_type;
 
                /* Get the read function that needs to be read next. */
                rf = c_head_get_root (read_heap);
@@ -344,6 +347,8 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                pthread_mutex_lock (&read_lock);
                pthread_cond_timedwait (&read_cond, &read_lock,
                                &rf->rf_next_read);
+               /* Must hold `real_lock' when accessing `rf->rf_type'. */
+               rf_type = rf->rf_type;
                pthread_mutex_unlock (&read_lock);
 
                /* Check if we're supposed to stop.. This may have interrupted
@@ -355,9 +360,22 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                        break;
                }
 
+               /* The entry has been marked for deletion. The linked list
+                * entry has already been removed by `plugin_unregister_read'.
+                * All we have to do here is free the `read_func_t' and
+                * continue. */
+               if (rf_type == RF_REMOVE)
+               {
+                       DEBUG ("plugin_read_thread: Destroying the `%s' "
+                                       "callback.", rf->rf_name);
+                       destroy_callback ((callback_func_t *) rf);
+                       rf = NULL;
+                       continue;
+               }
+
                DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name);
 
-               if (rf->rf_type == RF_SIMPLE)
+               if (rf_type == RF_SIMPLE)
                {
                        int (*callback) (void);
 
@@ -368,6 +386,8 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                {
                        plugin_read_cb callback;
 
+                       assert (rf_type == RF_COMPLEX);
+
                        callback = rf->rf_callback;
                        status = (*callback) (&rf->rf_udata);
                }
@@ -641,22 +661,67 @@ static int plugin_compare_read_func (const void *arg0, const void *arg1)
                return (0);
 } /* int plugin_compare_read_func */
 
-int plugin_register_read (const char *name,
-               int (*callback) (void))
+/* Add a read function to both, the heap and a linked list. The linked list if
+ * used to look-up read functions, especially for the remove function. The heap
+ * is used to determine which plugin to read next. */
+static int plugin_insert_read (read_func_t *rf)
 {
-       read_func_t *rf;
+       int status;
+       llentry_t *le;
+
+       pthread_mutex_lock (&read_lock);
+
+       if (read_list == NULL)
+       {
+               read_list = llist_create ();
+               if (read_list == NULL)
+               {
+                       pthread_mutex_unlock (&read_lock);
+                       ERROR ("plugin_insert_read: read_list failed.");
+                       return (-1);
+               }
+       }
 
        if (read_heap == NULL)
        {
                read_heap = c_heap_create (plugin_compare_read_func);
                if (read_heap == NULL)
                {
-                       ERROR ("plugin_register_read: "
-                                       "c_heap_create failed.");
+                       pthread_mutex_unlock (&read_lock);
+                       ERROR ("plugin_insert_read: c_heap_create failed.");
                        return (-1);
                }
        }
 
+       le = llentry_create (rf->rf_name, rf);
+       if (le == NULL)
+       {
+               pthread_mutex_unlock (&read_lock);
+               ERROR ("plugin_insert_read: llentry_create failed.");
+               return (-1);
+       }
+
+       status = c_heap_insert (read_heap, rf);
+       if (status != 0)
+       {
+               pthread_mutex_unlock (&read_lock);
+               ERROR ("plugin_insert_read: c_heap_insert failed.");
+               llentry_destroy (le);
+               return (-1);
+       }
+
+       /* This does not fail. */
+       llist_append (read_list, le);
+
+       pthread_mutex_unlock (&read_lock);
+       return (0);
+} /* int plugin_insert_read */
+
+int plugin_register_read (const char *name,
+               int (*callback) (void))
+{
+       read_func_t *rf;
+
        rf = (read_func_t *) malloc (sizeof (read_func_t));
        if (rf == NULL)
        {
@@ -676,7 +741,7 @@ int plugin_register_read (const char *name,
        rf->rf_interval.tv_nsec = 0;
        rf->rf_effective_interval = rf->rf_interval;
 
-       return (c_heap_insert (read_heap, rf));
+       return (plugin_insert_read (rf));
 } /* int plugin_register_read */
 
 int plugin_register_complex_read (const char *name,
@@ -686,16 +751,6 @@ int plugin_register_complex_read (const char *name,
 {
        read_func_t *rf;
 
-       if (read_heap == NULL)
-       {
-               read_heap = c_heap_create (plugin_compare_read_func);
-               if (read_heap == NULL)
-               {
-                       ERROR ("plugin_register_read: c_heap_create failed.");
-                       return (-1);
-               }
-       }
-
        rf = (read_func_t *) malloc (sizeof (read_func_t));
        if (rf == NULL)
        {
@@ -724,7 +779,7 @@ int plugin_register_complex_read (const char *name,
                rf->rf_udata = *user_data;
        }
 
-       return (c_heap_insert (read_heap, rf));
+       return (plugin_insert_read (rf));
 } /* int plugin_register_complex_read */
 
 int plugin_register_write (const char *name,
@@ -816,12 +871,37 @@ int plugin_unregister_init (const char *name)
        return (plugin_unregister (list_init, name));
 }
 
-int plugin_unregister_read (const char *name)
+int plugin_unregister_read (const char *name) /* {{{ */
 {
-       /* TODO: Implement removal of a specific key from the heap. */
-       assert (0);
-       return (-1);
-}
+       llentry_t *le;
+       read_func_t *rf;
+
+       if (name == NULL)
+               return (-ENOENT);
+
+       pthread_mutex_lock (&read_lock);
+
+       if (read_list == NULL)
+       {
+               pthread_mutex_unlock (&read_lock);
+               return (-ENOENT);
+       }
+
+       le = llist_search (read_list, name);
+       llist_remove (read_list, le);
+
+       rf = le->value;
+       assert (rf != NULL);
+       rf->rf_type = RF_REMOVE;
+
+       pthread_mutex_unlock (&read_lock);
+
+       llentry_destroy (le);
+
+       DEBUG ("plugin_unregister_read: Marked `%s' for removal.", name);
+
+       return (0);
+} /* }}} int plugin_unregister_read */
 
 int plugin_unregister_write (const char *name)
 {
@@ -1093,6 +1173,12 @@ void plugin_shutdown_all (void)
        stop_read_threads ();
 
        destroy_all_callbacks (&list_init);
+
+       pthread_mutex_lock (&read_lock);
+       llist_destroy (read_list);
+       read_list = NULL;
+       pthread_mutex_unlock (&read_lock);
+
        destroy_read_heap ();
 
        plugin_flush (/* plugin = */ NULL, /* timeout = */ -1,
index 2505b55..956f826 100644 (file)
@@ -362,6 +362,7 @@ int uc_check_timeout (void)
     {
       DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''",
          keys[i]);
+      ce = NULL;
       status = c_avl_remove (cache_tree, keys[i],
          (void *) &key, (void *) &ce);
       if (status != 0)
@@ -370,7 +371,8 @@ int uc_check_timeout (void)
       }
       sfree (keys[i]);
       sfree (key);
-      cache_free (ce);
+      if (ce != NULL)
+        cache_free (ce);
       continue;
     }
 
@@ -611,16 +613,24 @@ int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_val
   {
     assert (ce != NULL);
 
-    ret_num = ce->values_num;
-    ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t));
-    if (ret == NULL)
+    /* remove missing values from getval */
+    if (ce->state == STATE_MISSING)
     {
-      ERROR ("utils_cache: uc_get_rate_by_name: malloc failed.");
       status = -1;
     }
     else
     {
-      memcpy (ret, ce->values_gauge, ret_num * sizeof (gauge_t));
+      ret_num = ce->values_num;
+      ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t));
+      if (ret == NULL)
+      {
+        ERROR ("utils_cache: uc_get_rate_by_name: malloc failed.");
+        status = -1;
+      }
+      else
+      {
+        memcpy (ret, ce->values_gauge, ret_num * sizeof (gauge_t));
+      }
     }
   }
   else
@@ -693,6 +703,10 @@ int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number)
   {
     char **temp;
 
+    /* remove missing values when list values */
+    if (value->state == STATE_MISSING)
+      continue;
+
     if (ret_times != NULL)
     {
       time_t *tmp_times;