From: Martin Sperl Date: Mon, 5 May 2014 16:18:55 +0000 (+0000) Subject: enabled template for rrdcached updates X-Git-Tag: v1.5.0-rc1~109^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F462%2Fhead;p=thirdparty%2Frrdtool-1.x.git enabled template for rrdcached updates this essentially "expands" the template to a "normal" update based on the structure from the file itself. This structure is cached in a GTree until the process dies - no validation is done to check if the file changed in the meantime --- diff --git a/configure.ac b/configure.ac index f74060ad..5fbcfb19 100644 --- a/configure.ac +++ b/configure.ac @@ -518,6 +518,7 @@ AM_CONDITIONAL(BUILD_LIBWRAP,[test $have_libwrap != no]) AM_CONDITIONAL(BUILD_RRDGRAPH,[test $enable_rrd_graph != no]) +EX_CHECK_ALL(glib-2.0, glib_check_version, glib.h, glib-2.0, 2.28.7, ftp://ftp.gtk.org/pub/glib/2.28/, "") CORE_LIBS="$LIBS" @@ -533,7 +534,6 @@ EX_CHECK_ALL(cairo, cairo_ps_surface_create, cairo-ps.h, EX_CHECK_ALL(pangocairo-1.0, pango_font_map_create_context, pango/pango.h, pangocairo, 1.28.4, http://ftp.gnome.org/pub/GNOME/sources/pango/1.28, "") fi -EX_CHECK_ALL(glib-2.0, glib_check_version, glib.h, glib-2.0, 2.28.7, ftp://ftp.gtk.org/pub/glib/2.28/, "") EX_CHECK_ALL(xml2, xmlParseFile, libxml/parser.h, libxml-2.0, 2.7.8, http://xmlsoft.org/downloads.html, /usr/include/libxml2) if test "$EX_CHECK_ALL_ERR" = "YES"; then diff --git a/src/rrd_update.c b/src/rrd_update.c index e9db085e..efa04824 100644 --- a/src/rrd_update.c +++ b/src/rrd_update.c @@ -26,6 +26,7 @@ #include "rrd_client.h" #include "rrd_update.h" +#include #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) @@ -362,6 +363,315 @@ rrd_info_t *rrd_update_v( return result; } +static char *rrd_get_file_template(const char *filename) /* {{{ */ +{ + rrd_t rrd; + rrd_file_t *rrd_file; + unsigned int i; + size_t len=0; + char *template = NULL; + + /* open file */ + rrd_init(&rrd); + rrd_file = rrd_open(filename, &rrd, RRD_READONLY); + if (rrd_file == NULL) + goto err_free; + + /* read the data from the rrd */ + for (i = 0; i < rrd.stat_head->ds_cnt; i++) { + len += strlen(rrd.ds_def[i].ds_nam)+1; + } + /* now that we got it allocate memory */ + template = malloc(len); + if (!template) + goto err_close; + template[0] = 0; + + /* fill in for real */ + for (i = 0; i < rrd.stat_head->ds_cnt; i++) { + if (i) + strcat(template,":"); + strcat(template,rrd.ds_def[i].ds_nam); + } + +err_close: + rrd_close(rrd_file); +err_free: + rrd_free(&rrd); + return (template); +} /* }}} const char *rrd_get_file_template */ + + +/* the file-template-cache implementation */ +static GTree *rrd_file_template_cache = NULL; +/* the neccesary functions for the gtree */ +static gint cache_compare_names (gconstpointer name1, + gconstpointer name2, + gpointer data) +{ + (void)(data); /* to avoid unused message */ + return (strcmp (name1, name2)); +} + +static void cache_destroy(gpointer data) +{ + free(data); +} + +static const char *rrd_get_file_template_format(const char *filename) /* {{{ */ +{ + char *format = NULL; + /* create rrd_file_template_cache if needed */ + if (!rrd_file_template_cache) { + rrd_file_template_cache = g_tree_new_full ( + cache_compare_names, + NULL, + cache_destroy, + cache_destroy); + if (!rrd_file_template_cache) + return NULL; + } + + /* fetch from cache */ + format = (char *) g_tree_lookup(rrd_file_template_cache, + filename); + if (format) + return format; + + /* fetch information from file */ + format = rrd_get_file_template(filename); + if (!format) + return NULL; + + /* create copy of filename */ + filename = strdup(filename); + if (!filename) + goto free_format; + + /* and add object to tree */ + g_tree_insert (rrd_file_template_cache, + (char *)filename, + format); + + return format; + +free_format: + free((void *)format); + return NULL; +} /* }}} const char *rrd_get_file_template_format */ + +static size_t _count_fields(const char *field) +{ + int c=1; + /* check for empty */ + if (!field) + return 0; + if (!field[0]) + return 0; + /* now count */ + while((field = strchr(field, ':'))) { + c++; + field++; + } + return c; +} + +static int _concat_field_n(char* string, const char *value, int field) { + const char *colon; + size_t len; + /* find the field */ + while (field) { + value = strchr(value, ':'); + if (!value) + return -1; + value++; + field--; + } + + /* get the end of string and calculate length */ + colon = strchr(value, ':'); + if (colon) { + len = colon-value; + } else { + len = strlen(value); + } + /* now concat strings */ + strncat(string, value, len); + + /* return 1 field */ + return 1; +} + +static int _concat_field( + char *string, + const char* tpl, + const char* value, + const char* field) +{ + int fieldidx=0; + size_t len = 0; + + /* get length */ + char *colon = strchr(field, ':'); + if (colon) { + len=colon-field; + } else + len=strlen(field); + + /* concat ":" */ + strcat(string, ":"); + + /* find field in tpl */ + while(tpl) { + /* check if it matches (including terminating 0 or :) */ + if((strncmp(tpl, field, len)==0)) { + if ((tpl[len] == 0) || (tpl[len] == ':')) { + return _concat_field_n( + string, value, fieldidx+1); + } + } + /* increment tpl */ + tpl = strchr(tpl, ':'); + if (tpl) + tpl++; + /* and also increase the field index */ + fieldidx++; + } + + /* concat "U" */ + strcat(string, "U"); + + /* and return "not found" */ + return 0; +} + +static char *rrd_map_template_to_values(const char *tpl, /* {{{ */ + const char *file_tpl, + const char *value) +{ + char *mapped = NULL; + size_t fields_count = 0; + size_t fields_tpl = _count_fields(tpl); + size_t fields_file_tpl = _count_fields(file_tpl); + size_t fields_value = _count_fields(value); + const char *ptr; + size_t len; + size_t i; + int ret; + + /* check number of fields*/ + if (fields_tpl != fields_value-1) { + rrd_set_error("rrd_map_template_to_values: " + "mismatch of number of fields in template (%zu) " + "with number of fields in values (%zu)", + fields_tpl,fields_value-1); + return NULL; + } + if (fields_tpl > fields_file_tpl) { + rrd_set_error("rrd_map_template_to_values: " + "number of fields in template (%zu) " + "bigger than number of fields in rrdfile (%zu)", + fields_tpl,fields_file_tpl); + return NULL; + } + + /* now calculate effective length and allocate it */ + len = strlen(value) /* length of the value */ + + 1 /* terminating null byte */ + + (fields_file_tpl-fields_tpl) /* number of fields that we have + * more in the file_template + * compared to the given template + */ + * 2 /* = strlen(":U") */; + + mapped = malloc(len); + if (!mapped) + return NULL; + mapped[0] = 0; + + /* first copy timestamp */ + if (_concat_field_n(mapped,value,0)<0) + goto err; + + /* now walk the list of fields from rrdtemplate*/ + ptr = file_tpl; + for (i=0; i 0) - rrd_set_error("Failed sending the values to rrdcached: %s", - rrd_strerror (rc)); + rrd_clear_error(); + if (tmplt) { + if (extra_flags != 0) { + rrd_set_error("The caching daemon cannot be used together with " + "templates and skip-past-updates yet."); + goto out; + } else { + rc = rrd_template_update( + argv[optind], /* file */ + tmplt, + argc - optind - 1, /* values_num */ + (const char *const *) (argv + optind + 1)); /* values */ + } + } else + rc = rrdc_update ( + argv[optind], /* file */ + argc - optind - 1, /* values_num */ + (const char *const *) (argv + optind + 1)); /* values */ + if (rc > 0) + if (!rrd_test_error()) + rrd_set_error("Failed sending the values to rrdcached: %s", + rrd_strerror (rc)); } out: