* 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,
use strict;
use warnings;
use lib ('../lib');
+use utf8;
use FindBin ('$RealBin');
use Carp (qw(confess cluck));
DataSources value
RRDTitle "Processes on {hostname}"
RRDVerticalLabel "Processes"
- RRDFormat "%5.1lf%s"
+ RRDFormat "%5.1lf"
DSName running Running
DSName sleeping Sleeping
DSName paging Paging
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
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 :
start
;;
condrestart)
- [ -f /var/lock/subsys/$prog ] && restart || :
+ [ -f /var/lock/subsys/$prog ] && stop && start || :
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
# 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. #
# #----------------------------------------------------------------#
=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
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
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
*
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;
}
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
{
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");
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) */
#include "plugin.h"
#include "configfile.h"
#include "utils_ignorelist.h"
+#include "utils_complain.h"
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
/* 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;
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;
}
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;
}
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);
#define RF_SIMPLE 0
#define RF_COMPLEX 1
+#define RF_REMOVE 65535
struct read_func_s
{
/* `read_func_t' "inherits" from `callback_func_t'.
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;
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);
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
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);
{
plugin_read_cb callback;
+ assert (rf_type == RF_COMPLEX);
+
callback = rf->rf_callback;
status = (*callback) (&rf->rf_udata);
}
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)
{
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,
{
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)
{
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,
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)
{
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,
{
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)
}
sfree (keys[i]);
sfree (key);
- cache_free (ce);
+ if (ce != NULL)
+ cache_free (ce);
continue;
}
{
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
{
char **temp;
+ /* remove missing values when list values */
+ if (value->state == STATE_MISSING)
+ continue;
+
if (ret_times != NULL)
{
time_t *tmp_times;