Alternate update interface, updatev. Returns info about CDPs written to disk as resul...
authorjake <jake@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 25 Apr 2003 18:35:08 +0000 (18:35 +0000)
committerjake <jake@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 25 Apr 2003 18:35:08 +0000 (18:35 +0000)
git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@201 a5681a0c-68f1-0310-ab6d-d61299d08faa

MakeMakefile
bindings/perl-shared/RRDs.pm
bindings/perl-shared/RRDs.xs
doc/rrdtool.pod
doc/rrdupdate.pod
src/rrd.h
src/rrd_create.c
src/rrd_info.c
src/rrd_tool.c
src/rrd_tool.h
src/rrd_update.c

index 28c62ed..8b311fa 100755 (executable)
@@ -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 
 
index 6146e43..fbe4478 100644 (file)
@@ -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<RRDs::updatev> 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<RRDs::fetch> 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.
index 1340b6f..474c9c4 100644 (file)
@@ -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
 
index 1040d58..40f2ea6 100644 (file)
@@ -50,6 +50,10 @@ Set up a new Round Robin Database (RRD). Check L<rrdcreate>.
 
 Store new data values into an RRD. Check L<rrdupdate>.
 
+=item B<updatev>
+
+Operation equivalent to B<update> except for output. Check L<rrdupdate>.
+
 =item B<graph>
 
 Create a graph from data stored in one or several RRD. Apart from
index d35b35b..394c49c 100644 (file)
@@ -6,7 +6,7 @@ rrdtool update - Store a new set of values into the rrd
 
 =head1 SYNOPSIS
 
-B<rrdtool> B<update> I<filename> 
+B<rrdtool> {B<update> | B<updatev>} I<filename> 
 S<[B<--template>|B<-t> I<ds-name>[B<:>I<ds-name>]...]> 
 S<B<N>|I<timestamp>B<:>I<value>[B<:>I<value>...]> 
 S<I<at-timestamp>B<@>I<value>[B<:>I<value>...]> 
@@ -20,6 +20,17 @@ which the data is written.
 
 =over 8
 
+=item B<updatev>
+
+This alternate version of B<update> takes the same arguments and
+performs the same function. The I<v> stands for I<verbose>, which
+describes the output returned. B<updatev> 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<filename>
 
 The name of the B<RRD> you want to update.
index 078e29e..a2478b2 100644 (file)
--- 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);
index 8aa46a7..e9dc2aa 100644 (file)
@@ -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:
index 1e76941..c183f7c 100644 (file)
@@ -9,13 +9,11 @@
 #include <stdarg.h>
 
 /* 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;i<rrd.stat_head->ds_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;i<rrd.stat_head->rra_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;
         }
     }
index 2cb4494..7ef262f 100644 (file)
@@ -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);
index 16bd4f2..92c99ae 100644 (file)
@@ -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 */
 
index 6ba9fdb..9e8063e 100644 (file)
@@ -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);
 }