Merge branch 'mg/jitter'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 18 Aug 2009 19:39:03 +0000 (21:39 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 18 Aug 2009 19:39:03 +0000 (21:39 +0200)
14 files changed:
ChangeLog
contrib/GenericJMX.conf
contrib/collection3/bin/graph.cgi
contrib/collection3/etc/collection.conf
contrib/fedora/init.d-collectd
src/Makefile.am
src/collectd.conf.in
src/collectd.conf.pod
src/java.c
src/libvirt.c
src/meta_data.c
src/network.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 b88d1a6..61a44b0 100644 (file)
@@ -61,7 +61,7 @@
       # Plugin instance:
       InstancePrefix "gc-"
       InstanceFrom "name"
-      ObjectName "java.lang:type=GarbageCollector,name=*"
+      ObjectName "java.lang:type=GarbageCollector,*"
 
       <Value>
         Type "invocations"
 
     # Memory usage by memory pool.
     <MBean "memory_pool">
-      ObjectName "java.lang:type=MemoryPool,name=*"
+      ObjectName "java.lang:type=MemoryPool,*"
       InstancePrefix "memory_pool-"
       InstanceFrom "name"
 
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 5e0b028..0ca6809 100644 (file)
@@ -455,7 +455,7 @@ endif
 
 if BUILD_PLUGIN_MADWIFI
 pkglib_LTLIBRARIES += madwifi.la
-madwifi_la_SOURCES = madwifi.c
+madwifi_la_SOURCES = madwifi.c madwifi.h
 madwifi_la_LDFLAGS = -module -avoid-version
 collectd_LDADD += "-dlopen" madwifi.la
 collectd_DEPENDENCIES += madwifi.la
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 7ab2172..49a3b78 100644 (file)
@@ -1832,6 +1832,11 @@ multicast, and IPv4 and IPv6 packets. The default is to not change this value.
 That means that multicast packets will be sent with a TTL of C<1> (one) on most
 operating systems.
 
+=item B<MaxPacketSize> I<1024-65535>
+
+Set the maximum size for datagrams received over the network. Packets larger
+than this will be truncated.
+
 =item B<Forward> I<true|false>
 
 If set to I<true>, write packets that were received via the network plugin to
@@ -2785,7 +2790,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 +2842,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..87b189f 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,56 @@ 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));
+  config_block->children_num += ci_copy->children_num;
+
+  /* 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 +3056,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 +3090,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 0e416bd..156028e 100644 (file)
@@ -54,9 +54,6 @@
 # include <gcrypt.h>
 #endif
 
-/* 1500 - 40 - 8  =  Ethernet packet - IPv6 header - UDP header */
-/* #define BUFF_SIZE 1452 */
-
 #ifndef IPV6_ADD_MEMBERSHIP
 # ifdef IPV6_JOIN_GROUP
 #  define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@@ -65,9 +62,6 @@
 # endif
 #endif /* !IP_ADD_MEMBERSHIP */
 
-/* Buffer size to allocate. */
-#define BUFF_SIZE 1024
-
 /*
  * Maximum size required for encryption / signing:
  *
@@ -245,7 +239,7 @@ typedef struct part_encryption_aes256_s part_encryption_aes256_t;
 
 struct receive_list_entry_s
 {
-  char data[BUFF_SIZE];
+  char *data;
   int  data_len;
   int  fd;
   struct receive_list_entry_s *next;
@@ -256,6 +250,7 @@ typedef struct receive_list_entry_s receive_list_entry_t;
  * Private variables
  */
 static int network_config_ttl = 0;
+static size_t network_config_packet_size = 1024;
 static int network_config_forward = 0;
 
 static sockent_t *sending_sockets = NULL;
@@ -278,7 +273,7 @@ static int       dispatch_thread_running = 0;
 static pthread_t dispatch_thread_id;
 
 /* Buffer in which to-be-sent network packets are constructed. */
-static char             send_buffer[BUFF_SIZE];
+static char            *send_buffer;
 static char            *send_buffer_ptr;
 static int              send_buffer_fill;
 static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
@@ -1431,6 +1426,10 @@ static int parse_packet (sockent_t *se, /* {{{ */
                }
        } /* while (buffer_size > sizeof (part_header_t)) */
 
+       if (status == 0 && buffer_size > 0)
+               WARNING ("network plugin: parse_packet: Received truncated "
+                               "packet, try increasing `MaxPacketSize'");
+
        return (status);
 } /* }}} int parse_packet */
 
@@ -2007,7 +2006,7 @@ static void *dispatch_thread (void __attribute__((unused)) *arg) /* {{{ */
 
 static int network_receive (void) /* {{{ */
 {
-       char buffer[BUFF_SIZE];
+       char buffer[network_config_packet_size];
        int  buffer_len;
 
        int i;
@@ -2067,6 +2066,12 @@ static int network_receive (void) /* {{{ */
                                return (-1);
                        }
                        memset (ent, 0, sizeof (receive_list_entry_t));
+                       ent->data = malloc (network_config_packet_size);
+                       if (ent->data == NULL)
+                       {
+                               ERROR ("network plugin: malloc failed.");
+                               return (-1);
+                       }
                        ent->fd = listen_sockets_pollfd[i].fd;
                        ent->next = NULL;
 
@@ -2551,6 +2556,24 @@ static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
   return (0);
 } /* }}} int network_config_set_ttl */
 
+static int network_config_set_buffer_size (const oconfig_item_t *ci) /* {{{ */
+{
+  int tmp;
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("network plugin: The `MaxPacketSize' config option needs exactly "
+        "one numeric argument.");
+    return (-1);
+  }
+
+  tmp = (int) ci->values[0].value.number;
+  if ((tmp >= 1024) && (tmp <= 65535))
+    network_config_packet_size = tmp;
+
+  return (0);
+} /* }}} int network_config_set_buffer_size */
+
 #if HAVE_LIBGCRYPT
 static int network_config_set_string (const oconfig_item_t *ci, /* {{{ */
     char **ret_string)
@@ -2774,6 +2797,8 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
       network_config_add_server (child);
     else if (strcasecmp ("TimeToLive", child->key) == 0)
       network_config_set_ttl (child);
+    else if (strcasecmp ("MaxPacketSize", child->key) == 0)
+      network_config_set_buffer_size (child);
     else if (strcasecmp ("Forward", child->key) == 0)
       network_config_set_boolean (child, &network_config_forward);
     else if (strcasecmp ("CacheFlush", child->key) == 0)
@@ -2791,7 +2816,7 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
 static int network_notification (const notification_t *n,
                user_data_t __attribute__((unused)) *user_data)
 {
-  char  buffer[BUFF_SIZE];
+  char  buffer[network_config_packet_size];
   char *buffer_ptr = buffer;
   int   buffer_free = sizeof (buffer);
   int   status;
@@ -2890,6 +2915,8 @@ static int network_shutdown (void)
        if (send_buffer_fill > 0)
                flush_buffer ();
 
+       free (send_buffer);
+
        /* TODO: Close `sending_sockets' */
 
        plugin_unregister_config ("network");
@@ -2912,6 +2939,12 @@ static int network_init (void)
 
        plugin_register_shutdown ("network", network_shutdown);
 
+       send_buffer = malloc (network_config_packet_size);
+       if (send_buffer == NULL)
+       {
+               ERROR ("network plugin: malloc failed.");
+               return (-1);
+       }
        network_init_buffer ();
 
        /* setup socket(s) and so on */
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;