From bf7d0302ab2ff46038f7002a9eab76f4105c3cee Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 25 Apr 2003 18:35:08 +0000 Subject: [PATCH] Alternate update interface, updatev. Returns info about CDPs written to disk as result of update. Output format is similar to rrd_info, a hash of key-values. git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@201 a5681a0c-68f1-0310-ab6d-d61299d08faa --- MakeMakefile | 2 +- bindings/perl-shared/RRDs.pm | 7 ++- bindings/perl-shared/RRDs.xs | 116 +++++++++++++++++++++++++------------------ doc/rrdtool.pod | 4 ++ doc/rrdupdate.pod | 13 ++++- src/rrd.h | 5 +- src/rrd_create.c | 4 +- src/rrd_info.c | 76 ++++++++++++++-------------- src/rrd_tool.c | 29 +++++++++-- src/rrd_tool.h | 8 ++- src/rrd_update.c | 109 +++++++++++++++++++++++++++++++++++----- 11 files changed, 264 insertions(+), 109 deletions(-) diff --git a/MakeMakefile b/MakeMakefile index 28c62ed..8b311fa 100755 --- a/MakeMakefile +++ b/MakeMakefile @@ -47,7 +47,7 @@ cp ltmain.sh config # If autoconf generates undefined MACRO errors, it may be unable # to find libtool.m4. Add the -I flag to aclocal to specify the # directory location of this file. -aclocal +aclocal -I $HOME/libtool/share/aclocal autoheader --warnings=all automake-1.7 --foreign --add-missing --force-missing --copy diff --git a/bindings/perl-shared/RRDs.pm b/bindings/perl-shared/RRDs.pm index 6146e43..fbe4478 100644 --- a/bindings/perl-shared/RRDs.pm +++ b/bindings/perl-shared/RRDs.pm @@ -7,7 +7,7 @@ use vars qw(@ISA $VERSION); require DynaLoader; -$VERSION = 1.000331; +$VERSION = 1.100001; bootstrap RRDs $VERSION; @@ -90,6 +90,11 @@ the values of the properties. print "$key = $$hash{$key}\n"; } +B also returns a pointer to hash. The keys of the hash +are concatenated strings of a timestamp, RRA index, and data source name for +each consolidated data point (CDP) written to disk as a result of the +current update call. The hash values are CDP values. + B is the most complex of the pack regarding return values. There are 4 values. Two normal integers, a pointer to an array and a pointer to a array of pointers. diff --git a/bindings/perl-shared/RRDs.xs b/bindings/perl-shared/RRDs.xs index 1340b6f..474c9c4 100644 --- a/bindings/perl-shared/RRDs.xs +++ b/bindings/perl-shared/RRDs.xs @@ -39,6 +39,58 @@ extern "C" { \ if (rrd_test_error()) XSRETURN_UNDEF; +#define hvs(VAL) hv_store_ent(hash, sv_2mortal(newSVpv(data->key,0)),VAL,0) + +#define rrdinfocode(name) \ + /* prepare argument list */ \ + argv = (char **) malloc((items+1)*sizeof(char *)); \ + argv[0] = "dummy"; \ + for (i = 0; i < items; i++) { \ + STRLEN len; \ + char *handle= SvPV(ST(i),len); \ + /* actually copy the data to make sure possible modifications \ + on the argv data does not backfire into perl */ \ + argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \ + strcpy(argv[i+1],handle); \ + } \ + optind=0; opterr=0; \ + rrd_clear_error(); \ + data=name(items+1, argv); \ + for (i=0; i < items; i++) { \ + free(argv[i+1]); \ + } \ + free(argv); \ + if (rrd_test_error()) XSRETURN_UNDEF; \ + hash = newHV(); \ + while (data) { \ + save=data; \ + /* the newSV will get copied by hv so we create it as a mortal \ + to make sure it does not keep hanging round after the fact */ \ + switch (data->type) { \ + case RD_I_VAL: \ + if (isnan(data->value.u_val)) \ + hvs(&PL_sv_undef); \ + else \ + hvs(newSVnv(data->value.u_val)); \ + break; \ + case RD_I_INT: \ + hvs(newSViv(data->value.u_int)); \ + break; \ + case RD_I_CNT: \ + hvs(newSViv(data->value.u_cnt)); \ + break; \ + case RD_I_STR: \ + hvs(newSVpv(data->value.u_str,0)); \ + rrd_freemem(data->value.u_str); \ + break; \ + } \ + rrd_freemem(data->key); \ + data = data->next; \ + rrd_freemem(save); \ + } \ + rrd_freemem(data); \ + RETVAL = newRV_noinc((SV*)hash); + /* * should not be needed if libc is linked (see ntmake.pl) #ifdef WIN32 @@ -289,54 +341,20 @@ rrd_info(...) char **argv; HV *hash; CODE: - /* prepare argument list */ - argv = (char **) malloc((items+1)*sizeof(char *)); - argv[0] = "dummy"; - for (i = 0; i < items; i++) { - STRLEN len; - char *handle= SvPV(ST(i),len); - /* actually copy the data to make sure possible modifications - on the argv data does not backfire into perl */ - argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); - strcpy(argv[i+1],handle); - } - optind=0; opterr=0; - rrd_clear_error(); - data=rrd_info(items+1, argv); - for (i=0; i < items; i++) { - free(argv[i+1]); - } - free(argv); - if (rrd_test_error()) XSRETURN_UNDEF; - hash = newHV(); - while (data) { - save=data; - /* the newSV will get copied by hv so we create it as a mortal to make sure - it does not keep hanging round after the fact */ -#define hvs(VAL) hv_store_ent(hash, sv_2mortal(newSVpv(data->key,0)),VAL,0) - switch (data->type) { - case RD_I_VAL: - if (isnan(data->value.u_val)) - hvs(&PL_sv_undef); - else - hvs(newSVnv(data->value.u_val)); - break; - case RD_I_CNT: - hvs(newSViv(data->value.u_cnt)); - break; - case RD_I_STR: - hvs(newSVpv(data->value.u_str,0)); - rrd_freemem(data->value.u_str); - break; - } -#undefine hvs - rrd_freemem(data->key); - data = data->next; - rrd_freemem(save); - } - rrd_freemem(data); - RETVAL = newRV_noinc((SV*)hash); - OUTPUT: - RETVAL + rrdinfocode(rrd_info); + OUTPUT: + RETVAL +SV* +rrd_updatev(...) + PROTOTYPE: @ + PREINIT: + info_t *data,*save; + int i; + char **argv; + HV *hash; + CODE: + rrdinfocode(rrd_update_v); + OUTPUT: + RETVAL diff --git a/doc/rrdtool.pod b/doc/rrdtool.pod index 1040d58..40f2ea6 100644 --- a/doc/rrdtool.pod +++ b/doc/rrdtool.pod @@ -50,6 +50,10 @@ Set up a new Round Robin Database (RRD). Check L. Store new data values into an RRD. Check L. +=item B + +Operation equivalent to B except for output. Check L. + =item B Create a graph from data stored in one or several RRD. Apart from diff --git a/doc/rrdupdate.pod b/doc/rrdupdate.pod index d35b35b..394c49c 100644 --- a/doc/rrdupdate.pod +++ b/doc/rrdupdate.pod @@ -6,7 +6,7 @@ rrdtool update - Store a new set of values into the rrd =head1 SYNOPSIS -B B I +B {B | B} I S<[B<--template>|B<-t> I[B<:>I]...]> S|IB<:>I[B<:>I...]> SB<@>I[B<:>I...]> @@ -20,6 +20,17 @@ which the data is written. =over 8 +=item B + +This alternate version of B takes the same arguments and +performs the same function. The I stands for I, which +describes the output returned. B returns a list of any and all +consolidated data points (CDPs) written to disk as a result of the +invocation of update. The values are indexed by timestamp (time_t), +RRA (index number), and data source (name). Note that depending +on the arguments of the current and previous call to update, the +list may have no entries or a large number of entries. + =item I The name of the B you want to update. diff --git a/src/rrd.h b/src/rrd.h index 078e29e..a2478b2 100644 --- a/src/rrd.h +++ b/src/rrd.h @@ -5,6 +5,9 @@ ***************************************************************************** * $Id$ * $Log$ + * Revision 1.5 2003/04/25 18:35:08 jake + * Alternate update interface, updatev. Returns info about CDPs written to disk as result of update. Output format is similar to rrd_info, a hash of key-values. + * * Revision 1.4 2003/04/01 22:52:23 jake * Fix Win32 build. VC++ 6.0 and 7.0 now use the thread-safe code. * @@ -63,7 +66,7 @@ int rrd_xport(int, char **, int *, time_t *, time_t *, int rrd_create_r(char *filename, unsigned long pdp_step, time_t last_up, int argc, char **argv); -/* NOTE: rrd_update_r is only thread-safe if no at-style time +/* NOTE: rrd_update_r are only thread-safe if no at-style time specifications get used!!! */ int rrd_update_r(char *filename, char *_template, int argc, char **argv); diff --git a/src/rrd_create.c b/src/rrd_create.c index 8aa46a7..e9dc2aa 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -170,6 +170,8 @@ rrd_create_r(char *filename, break; case DST_CDEF: parseCDEF_DS(&argv[i][offset+3],&rrd, rrd.stat_head->ds_cnt); + /* need to mark the file w/ current version */ + strcpy(rrd.stat_head->version,RRD_VERSION); break; default: rrd_set_error("invalid DS type specified"); @@ -211,7 +213,7 @@ rrd_create_r(char *filename, rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].u_val = 1.0/288; rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = rrd.stat_head -> rra_cnt; - /* need to mark the file version */ + /* need to mark the file w/ current version */ strcpy(rrd.stat_head->version,RRD_VERSION); break; case CF_DEVSEASONAL: diff --git a/src/rrd_info.c b/src/rrd_info.c index 1e76941..c183f7c 100644 --- a/src/rrd_info.c +++ b/src/rrd_info.c @@ -9,13 +9,11 @@ #include /* proto */ -static char * sprintf_alloc(char *, ...); -static info_t *push(info_t *, char *, enum info_type, infoval); info_t *rrd_info(int, char **); info_t *rrd_info_r(char *filename); /* allocate memory for string */ -static char * +char * sprintf_alloc(char *fmt, ...) { #ifdef HAVE_VSNPRINTF int maxlen = 50; @@ -36,9 +34,10 @@ sprintf_alloc(char *fmt, ...) { va_end(argp); return str; } - -static info_t -*push(info_t *info, char *key, enum info_type type, infoval value){ +/* the function formerly known as push was renamed info_push because + * it is now used outside the scope of this file */ +info_t +*info_push(info_t *info, char *key, enum info_type type, infoval value){ info_t *next; next = malloc(sizeof(*next)); next->next = (info_t *) 0; @@ -53,6 +52,9 @@ static info_t case RD_I_CNT: next->value.u_cnt = value.u_cnt; break; + case RD_I_INT: + next->value.u_int = value.u_int; + break; case RD_I_STR: next->value.u_str = malloc(sizeof(char)*(strlen(value.u_str)+1)); strcpy(next->value.u_str,value.u_str); @@ -94,22 +96,22 @@ rrd_info_r(char *filename) { fclose(in_file); info.u_str=filename; - cd=push(NULL,sprintf_alloc("filename"), RD_I_STR, info); + cd=info_push(NULL,sprintf_alloc("filename"), RD_I_STR, info); data=cd; info.u_str=rrd.stat_head->version; - cd=push(cd,sprintf_alloc("rrd_version"), RD_I_STR, info); + cd=info_push(cd,sprintf_alloc("rrd_version"), RD_I_STR, info); info.u_cnt=rrd.stat_head->pdp_step; - cd=push(cd,sprintf_alloc("step"), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("step"), RD_I_CNT, info); info.u_cnt=rrd.live_head->last_up; - cd=push(cd,sprintf_alloc("last_update"), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("last_update"), RD_I_CNT, info); for(i=0;ids_cnt;i++){ info.u_str=rrd.ds_def[i].dst; - cd=push(cd,sprintf_alloc("ds[%s].type", rrd.ds_def[i].ds_nam), RD_I_STR, info); + cd=info_push(cd,sprintf_alloc("ds[%s].type", rrd.ds_def[i].ds_nam), RD_I_STR, info); current_ds = dst_conv(rrd.ds_def[i].dst); switch (current_ds) { @@ -119,71 +121,71 @@ rrd_info_r(char *filename) { rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]), rrd.ds_def, &buffer); info.u_str = buffer; - cd=push(cd,sprintf_alloc("ds[%s].cdef",rrd.ds_def[i].ds_nam),RD_I_STR,info); + cd=info_push(cd,sprintf_alloc("ds[%s].cdef",rrd.ds_def[i].ds_nam),RD_I_STR,info); free(buffer); } break; default: info.u_cnt=rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt; - cd=push(cd,sprintf_alloc("ds[%s].minimal_heartbeat",rrd.ds_def[i].ds_nam), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("ds[%s].minimal_heartbeat",rrd.ds_def[i].ds_nam), RD_I_CNT, info); info.u_val=rrd.ds_def[i].par[DS_min_val].u_val; - cd=push(cd,sprintf_alloc("ds[%s].min",rrd.ds_def[i].ds_nam), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("ds[%s].min",rrd.ds_def[i].ds_nam), RD_I_VAL, info); info.u_val=rrd.ds_def[i].par[DS_max_val].u_val; - cd=push(cd,sprintf_alloc("ds[%s].max",rrd.ds_def[i].ds_nam), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("ds[%s].max",rrd.ds_def[i].ds_nam), RD_I_VAL, info); break; } info.u_str=rrd.pdp_prep[i].last_ds; - cd=push(cd,sprintf_alloc("ds[%s].last_ds", rrd.ds_def[i].ds_nam), RD_I_STR, info); + cd=info_push(cd,sprintf_alloc("ds[%s].last_ds", rrd.ds_def[i].ds_nam), RD_I_STR, info); info.u_val=rrd.pdp_prep[i].scratch[PDP_val].u_val; - cd=push(cd,sprintf_alloc("ds[%s].value", rrd.ds_def[i].ds_nam), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("ds[%s].value", rrd.ds_def[i].ds_nam), RD_I_VAL, info); info.u_cnt=rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt; - cd=push(cd,sprintf_alloc("ds[%s].unknown_sec", rrd.ds_def[i].ds_nam), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("ds[%s].unknown_sec", rrd.ds_def[i].ds_nam), RD_I_CNT, info); } for(i=0;irra_cnt;i++){ info.u_str=rrd.rra_def[i].cf_nam; - cd=push(cd,sprintf_alloc("rra[%d].cf", i), RD_I_STR, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cf", i), RD_I_STR, info); current_cf = cf_conv(rrd.rra_def[i].cf_nam); info.u_cnt=rrd.rra_def[i].row_cnt; - cd=push(cd,sprintf_alloc("rra[%d].rows",i), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("rra[%d].rows",i), RD_I_CNT, info); info.u_cnt=rrd.rra_def[i].pdp_cnt; - cd=push(cd,sprintf_alloc("rra[%d].pdp_per_row",i), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("rra[%d].pdp_per_row",i), RD_I_CNT, info); switch(current_cf) { case CF_HWPREDICT: info.u_val=rrd.rra_def[i].par[RRA_hw_alpha].u_val; - cd=push(cd,sprintf_alloc("rra[%d].alpha",i),RD_I_VAL,info); + cd=info_push(cd,sprintf_alloc("rra[%d].alpha",i),RD_I_VAL,info); info.u_val=rrd.rra_def[i].par[RRA_hw_beta].u_val; - cd=push(cd,sprintf_alloc("rra[%d].beta",i),RD_I_VAL,info); + cd=info_push(cd,sprintf_alloc("rra[%d].beta",i),RD_I_VAL,info); break; case CF_SEASONAL: case CF_DEVSEASONAL: info.u_val=rrd.rra_def[i].par[RRA_seasonal_gamma].u_val; - cd=push(cd,sprintf_alloc("rra[%d].gamma",i),RD_I_VAL,info); + cd=info_push(cd,sprintf_alloc("rra[%d].gamma",i),RD_I_VAL,info); break; case CF_FAILURES: info.u_val=rrd.rra_def[i].par[RRA_delta_pos].u_val; - cd=push(cd,sprintf_alloc("rra[%d].delta_pos",i),RD_I_VAL,info); + cd=info_push(cd,sprintf_alloc("rra[%d].delta_pos",i),RD_I_VAL,info); info.u_val=rrd.rra_def[i].par[RRA_delta_neg].u_val; - cd=push(cd,sprintf_alloc("rra[%d].delta_neg",i),RD_I_VAL,info); + cd=info_push(cd,sprintf_alloc("rra[%d].delta_neg",i),RD_I_VAL,info); info.u_cnt=rrd.rra_def[i].par[RRA_failure_threshold].u_cnt; - cd=push(cd,sprintf_alloc("rra[%d].failure_threshold",i),RD_I_CNT,info); + cd=info_push(cd,sprintf_alloc("rra[%d].failure_threshold",i),RD_I_CNT,info); info.u_cnt=rrd.rra_def[i].par[RRA_window_len].u_cnt; - cd=push(cd,sprintf_alloc("rra[%d].window_length",i),RD_I_CNT,info); + cd=info_push(cd,sprintf_alloc("rra[%d].window_length",i),RD_I_CNT,info); break; case CF_DEVPREDICT: break; default: info.u_val=rrd.rra_def[i].par[RRA_cdp_xff_val].u_val; - cd=push(cd,sprintf_alloc("rra[%d].xff",i),RD_I_VAL,info); + cd=info_push(cd,sprintf_alloc("rra[%d].xff",i),RD_I_VAL,info); break; } @@ -192,19 +194,19 @@ rrd_info_r(char *filename) { { case CF_HWPREDICT: info.u_val=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_intercept].u_val; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].intercept",i,ii), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].intercept",i,ii), RD_I_VAL, info); info.u_val=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_slope].u_val; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].slope",i,ii), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].slope",i,ii), RD_I_VAL, info); info.u_cnt=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_null_count].u_cnt; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].NaN_count",i,ii), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].NaN_count",i,ii), RD_I_CNT, info); break; case CF_SEASONAL: info.u_val=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_seasonal].u_val; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].seasonal",i,ii), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].seasonal",i,ii), RD_I_VAL, info); break; case CF_DEVSEASONAL: info.u_val=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_seasonal_deviation].u_val; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].deviation",i,ii), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].deviation",i,ii), RD_I_VAL, info); break; case CF_DEVPREDICT: break; @@ -218,14 +220,14 @@ rrd_info_r(char *filename) { history[j] = (violations_array[j] == 1) ? '1' : '0'; history[j] = '\0'; info.u_str = history; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].history",i,ii), RD_I_STR, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].history",i,ii), RD_I_STR, info); } break; default: info.u_val=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_val].u_val; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].value",i,ii), RD_I_VAL, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].value",i,ii), RD_I_VAL, info); info.u_cnt=rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_unkn_pdp_cnt].u_cnt; - cd=push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].unknown_datapoints",i,ii), RD_I_CNT, info); + cd=info_push(cd,sprintf_alloc("rra[%d].cdp_prep[%d].unknown_datapoints",i,ii), RD_I_CNT, info); break; } } diff --git a/src/rrd_tool.c b/src/rrd_tool.c index 2cb4494..7ef262f 100644 --- a/src/rrd_tool.c +++ b/src/rrd_tool.c @@ -31,7 +31,7 @@ void PrintUsage(char *cmd) "Usage: rrdtool [options] command command_options\n\n"; char help_list[] = - "Valid commands: create, update, graph, dump, restore,\n" + "Valid commands: create, update, updatev, graph, dump, restore,\n" "\t\tlast, info, fetch, tune, resize, xport\n\n"; char help_listremote[] = @@ -68,6 +68,15 @@ void PrintUsage(char *cmd) "\t\ttime|N:value[:value...]\n\n" "\t\tat-time@value[:value...]\n\n" "\t\t[ time:value[:value...] ..]\n\n"; + + char help_updatev[] = + "* updatev - a verbose verion of update\n" + "\treturns information about values, RRAs, and datasources updated\n\n" + "\trrdtool updatev filename\n" + "\t\t--template|-t ds-name:ds-name:...\n" + "\t\ttime|N:value[:value...]\n\n" + "\t\tat-time@value[:value...]\n\n" + "\t\t[ time:value[:value...] ..]\n\n"; char help_fetch[] = "* fetch - fetch data out of an RRD\n\n" @@ -158,7 +167,7 @@ void PrintUsage(char *cmd) enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT, - C_QUIT, C_LS, C_CD, C_MKDIR }; + C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV }; int help_cmd = C_NONE; @@ -176,6 +185,8 @@ void PrintUsage(char *cmd) help_cmd = C_LAST; else if (!strcmp(cmd,"update")) help_cmd = C_UPDATE; + else if (!strcmp(cmd,"updatev")) + help_cmd = C_UPDATEV; else if (!strcmp(cmd,"fetch")) help_cmd = C_FETCH; else if (!strcmp(cmd,"graph")) @@ -222,6 +233,9 @@ void PrintUsage(char *cmd) case C_UPDATE: fputs(help_update, stdout); break; + case C_UPDATEV: + fputs(help_updatev, stdout); + break; case C_FETCH: fputs(help_fetch, stdout); break; @@ -467,9 +481,13 @@ int HandleInputLine(int argc, char **argv, FILE* out) rrd_create(argc-1, &argv[1]); else if (strcmp("dump", argv[1]) == 0) rrd_dump(argc-1, &argv[1]); - else if (strcmp("info", argv[1]) == 0){ + else if (strcmp("info", argv[1]) == 0 + || strcmp("updatev", argv[1]) == 0){ info_t *data,*save; - data=rrd_info(argc-1, &argv[1]); + if (strcmp("info",argv[1]) == 0) + data=rrd_info(argc-1, &argv[1]); + else + data=rrd_update_v(argc-1, &argv[1]); while (data) { save=data; printf ("%s = ", data->key); @@ -485,6 +503,9 @@ int HandleInputLine(int argc, char **argv, FILE* out) case RD_I_CNT: printf ("%lu", data->value.u_cnt); break; + case RD_I_INT: + printf ("%d", data->value.u_int); + break; case RD_I_STR: printf ("\"%s\"", data->value.u_str); free(data->value.u_str); diff --git a/src/rrd_tool.h b/src/rrd_tool.h index 16bd4f2..92c99ae 100644 --- a/src/rrd_tool.h +++ b/src/rrd_tool.h @@ -133,12 +133,14 @@ char *strtok_r(char *str, const char *sep, char **last); /* rrd info interface */ enum info_type { RD_I_VAL=0, RD_I_CNT, - RD_I_STR }; + RD_I_STR, + RD_I_INT }; typedef union infoval { unsigned long u_cnt; rrd_value_t u_val; char *u_str; + int u_int; } infoval; typedef struct info_t { @@ -148,8 +150,10 @@ typedef struct info_t { struct info_t *next; } info_t; - info_t *rrd_info(int, char **); +info_t *rrd_update_v(int, char **); +char * sprintf_alloc(char *, ...); +info_t *info_push(info_t *, char *, enum info_type, infoval); /* HELPER FUNCTIONS */ diff --git a/src/rrd_update.c b/src/rrd_update.c index 6ba9fdb..9e8063e 100644 --- a/src/rrd_update.c +++ b/src/rrd_update.c @@ -5,6 +5,9 @@ ***************************************************************************** * $Id$ * $Log$ + * Revision 1.9 2003/04/25 18:35:08 jake + * Alternate update interface, updatev. Returns info about CDPs written to disk as result of update. Output format is similar to rrd_info, a hash of key-values. + * * Revision 1.8 2003/03/31 21:22:12 oetiker * enables RRDtool updates with microsecond or in case of windows millisecond * precision. This is needed to reduce time measurement error when archive step @@ -113,10 +116,13 @@ static void normalize_time(struct timeval *t) /* Local prototypes */ int LockRRD(FILE *rrd_file); -void write_RRA_row (rrd_t *rrd, unsigned long rra_idx, +info_t *write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, - unsigned short CDP_scratch_idx, FILE *rrd_file); + unsigned short CDP_scratch_idx, FILE *rrd_file, + info_t *pcdp_summary, time_t *rra_time); int rrd_update_r(char *filename, char *template, int argc, char **argv); +int _rrd_update(char *filename, char *template, int argc, char **argv, + info_t*); #define IFDNAN(X,Y) (isnan(X) ? (Y) : (X)); @@ -141,6 +147,52 @@ main(int argc, char **argv){ } #endif +info_t *rrd_update_v(int argc, char **argv) +{ + char *template = NULL; + info_t *result = NULL; + infoval rc; + + while (1) { + static struct option long_options[] = + { + {"template", required_argument, 0, 't'}, + {0,0,0,0} + }; + int option_index = 0; + int opt; + opt = getopt_long(argc, argv, "t:", + long_options, &option_index); + + if (opt == EOF) + break; + + switch(opt) { + case 't': + template = optarg; + break; + + case '?': + rrd_set_error("unknown option '%s'",argv[optind-1]); + rc.u_int = -1; + goto end_tag; + } + } + + /* need at least 2 arguments: filename, data. */ + if (argc-optind < 2) { + rrd_set_error("Not enough arguments"); + rc.u_int = -1; + goto end_tag; + } + result = info_push(NULL,sprintf_alloc("return_value"),RD_I_INT,rc); + rc.u_int = _rrd_update(argv[optind], template, + argc - optind - 1, argv + optind + 1, result); + result->value.u_int = rc.u_int; +end_tag: + return result; +} + int rrd_update(int argc, char **argv) { @@ -165,7 +217,7 @@ rrd_update(int argc, char **argv) case 't': template = optarg; break; - + case '?': rrd_set_error("unknown option '%s'",argv[optind-1]); return(-1); @@ -178,8 +230,8 @@ rrd_update(int argc, char **argv) return -1; } - - rc = rrd_update_r(argv[optind], template, + + rc = rrd_update_r(argv[optind], template, argc - optind - 1, argv + optind + 1); return rc; } @@ -187,6 +239,13 @@ rrd_update(int argc, char **argv) int rrd_update_r(char *filename, char *template, int argc, char **argv) { + return _rrd_update(filename, template, argc, argv, NULL); +} + +int +_rrd_update(char *filename, char *template, int argc, char **argv, + info_t *pcdp_summary) +{ int arg_i = 2; short j; @@ -229,6 +288,7 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) FILE *rrd_file; rrd_t rrd; time_t current_time; + time_t rra_time; /* time of update for a RRA */ unsigned long current_time_usec; /* microseconds part of current time */ struct timeval tmp_time; /* used for time conversion */ @@ -1109,7 +1169,14 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) fprintf(stderr," -- RRA Postseek %ld\n",ftell(rrd_file)); #endif scratch_idx = CDP_primary_val; - write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file); + if (pcdp_summary != NULL) + { + rra_time = (current_time - current_time + % (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) + - ((rra_step_cnt[i]-1)*rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step); + } + pcdp_summary = write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file, + pcdp_summary, &rra_time); if (rrd_test_error()) break; /* write other rows of the bulk update, if any */ @@ -1136,7 +1203,14 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) #endif rra_current = rra_start; } - write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file); + if (pcdp_summary != NULL) + { + rra_time = (current_time - current_time + % (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) + - ((rra_step_cnt[i]-2)*rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step); + } + pcdp_summary = write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file, + pcdp_summary, &rra_time); } if (rrd_test_error()) @@ -1345,12 +1419,14 @@ LockRRD(FILE *rrdfile) } -void -write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, - unsigned short CDP_scratch_idx, FILE *rrd_file) +info_t +*write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, + unsigned short CDP_scratch_idx, FILE *rrd_file, + info_t *pcdp_summary, time_t *rra_time) { unsigned long ds_idx, cdp_idx; - + infoval iv; + for (ds_idx = 0; ds_idx < rrd -> stat_head -> ds_cnt; ds_idx++) { /* compute the cdp index */ @@ -1360,7 +1436,15 @@ write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val,ftell(rrd_file), rrd -> rra_def[rra_idx].cf_nam); #endif - + if (pcdp_summary != NULL) + { + iv.u_val = rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val; + /* append info to the return hash */ + pcdp_summary = info_push(pcdp_summary, + sprintf_alloc("[%d]RRA[%lu]DS[%s]", + *rra_time, rra_idx, rrd->ds_def[ds_idx].ds_nam), + RD_I_VAL, iv); + } if(fwrite(&(rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val), sizeof(rrd_value_t),1,rrd_file) != 1) { @@ -1369,4 +1453,5 @@ write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, } *rra_current += sizeof(rrd_value_t); } + return (pcdp_summary); } -- 2.11.0