Code

enables RRDtool updates with microsecond or in case of windows millisecond
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Mon, 31 Mar 2003 21:22:12 +0000 (21:22 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Mon, 31 Mar 2003 21:22:12 +0000 (21:22 +0000)
precision. This is needed to reduce time measurement error when archive step
is small. (<30s) --  Sasha Mikheev <sasha@avalon-net.co.il>

git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@196 a5681a0c-68f1-0310-ab6d-d61299d08faa

src/rrd_format.h
src/rrd_open.c
src/rrd_update.c

index b9fa2c266b8cef8d800c60ff3b163650c75dbc48..1a58ebb6f8cf266b652aafff9871494da7c4030f 100644 (file)
@@ -19,7 +19,9 @@
  *****************************************************************************/
 
 #define RRD_COOKIE    "RRD"
-#define RRD_VERSION   "0002"
+/* #define RRD_VERSION   "0002" */
+/* changed because microsecond precision requires another field */
+#define RRD_VERSION   "0003"
 #define FLOAT_COOKIE  8.642135E130
 
 #include "rrd_nan_inf.h"
@@ -248,6 +250,8 @@ typedef struct rra_def_t {
 
 typedef struct live_head_t {
     time_t           last_up;            /* when was rrd last updated */
+    long            last_up_usec;       /* micro seconds part of the
+                                           update timestamp. Always >= 0 */
 } live_head_t;
 
 
index b85ceefae6e98e1f0bf3c0b4cce583c6923a2311..f345e28f71839e53ad16190db1c469fcfe6b52e6 100644 (file)
@@ -5,6 +5,11 @@
  *****************************************************************************
  * $Id$
  * $Log$
+ * Revision 1.7  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
+ * is small. (<30s) --  Sasha Mikheev <sasha@avalon-net.co.il>
+ *
  * Revision 1.6  2003/02/13 07:05:27  oetiker
  * Find attached the patch I promised to send to you. Please note that there
  * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c
@@ -52,6 +57,8 @@ rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)
 
     
     char *mode = NULL;
+    int version;
+    
     rrd_init(rrd);
     if (rdwr == RRD_READONLY) {
 #ifndef WIN32
@@ -90,7 +97,8 @@ rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)
 
 
     MYFREAD(rrd->stat_head, stat_head_t,  1)
-    
+    version = atoi(rrd->stat_head->version);
+
        /* lets do some test if we are on track ... */
        if (strncmp(rrd->stat_head->cookie,RRD_COOKIE,4) != 0){
            rrd_set_error("'%s' is not an RRD file",file_name);
@@ -98,7 +106,7 @@ rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)
            fclose(*in_file);
            return(-1);}
 
-        if (atoi(rrd->stat_head->version) > atoi(RRD_VERSION)){
+        if (version > atoi(RRD_VERSION)){
            rrd_set_error("can't handle RRD file version %s",
                        rrd->stat_head->version);
            free(rrd->stat_head);
@@ -113,7 +121,19 @@ rrd_open(char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)
 
     MYFREAD(rrd->ds_def,    ds_def_t,     rrd->stat_head->ds_cnt)
     MYFREAD(rrd->rra_def,   rra_def_t,    rrd->stat_head->rra_cnt)
-    MYFREAD(rrd->live_head,   live_head_t,  1)
+    /* handle different format for the live_head */
+    if(version < 3) {
+           rrd->live_head = (live_head_t *)malloc(sizeof(live_head_t));
+           if(rrd->live_head == NULL) {
+               rrd_set_error("live_head_t malloc");
+               fclose(*in_file); 
+               return (-1);
+           }
+            fread(&rrd->live_head->last_up, sizeof(long), 1, *in_file); 
+    }
+    else {
+           MYFREAD(rrd->live_head, live_head_t, 1)
+    }
     MYFREAD(rrd->pdp_prep,  pdp_prep_t,   rrd->stat_head->ds_cnt)
     MYFREAD(rrd->cdp_prep,  cdp_prep_t,   (rrd->stat_head->rra_cnt
                                             * rrd->stat_head->ds_cnt))
index a6f93a8fef9e3a83b9e0a3e922b77ea74beaa9fa..6ba9fdb0233f81dea3633fefe777515bf9f466f8 100644 (file)
@@ -5,6 +5,11 @@
  *****************************************************************************
  * $Id$
  * $Log$
+ * 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
+ * is small. (<30s) --  Sasha Mikheev <sasha@avalon-net.co.il>
+ *
  * Revision 1.7  2003/02/13 07:05:27  oetiker
  * Find attached the patch I promised to send to you. Please note that there
  * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c
 
 #include "rrd_is_thread_safe.h"
 
+#ifdef WIN32
+/*
+ * WIN32 does not have gettimeofday    and struct timeval. This is a quick and dirty
+ * replacement.
+ */
+#include <sys/timeb.h>
+
+struct timeval {
+       time_t tv_sec; /* seconds */
+       long tv_usec;  /* microseconds */
+};
+
+struct __timezone {
+       int  tz_minuteswest; /* minutes W of Greenwich */
+       int  tz_dsttime;     /* type of dst correction */
+};
+
+static gettimeofday(struct timeval *t, struct __timezone *tz) {
+       
+       struct timeb current_time;
+
+       _ftime(&current_time);
+       
+       t->tv_sec  = current_time.time;
+       t->tv_usec = current_time.millitm * 1000;
+}
+
+#endif
+/*
+ * normilize time as returned by gettimeofday. usec part must
+ * be always >= 0
+ */
+static void normalize_time(struct timeval *t)
+{
+       if(t->tv_usec < 0) {
+               t->tv_sec--;
+               t->tv_usec += 1000000L;
+       }
+}
+
 /* Local prototypes */
 int LockRRD(FILE *rrd_file);
 void write_RRA_row (rrd_t *rrd, unsigned long rra_idx, 
@@ -123,7 +168,6 @@ rrd_update(int argc, char **argv)
                        
                case '?':
                        rrd_set_error("unknown option '%s'",argv[optind-1]);
-                       /*            rrd_free(&rrd); */
                        return(-1);
                }
     }
@@ -158,7 +202,7 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
     unsigned long    rra_current;        /* byte pointer to the current write
                                          * spot in the rrd file. */
     unsigned long    rra_pos_tmp;        /* temporary byte pointer. */
-    unsigned long    interval,
+    double           interval,
        pre_int,post_int;                /* interval between this and
                                          * the last run */
     unsigned long    proc_pdp_st;        /* which pdp_st was the last
@@ -184,7 +228,10 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
 
     FILE             *rrd_file;
     rrd_t            rrd;
-    time_t           current_time = time(NULL);
+    time_t           current_time;
+    unsigned long    current_time_usec;  /* microseconds part of current time */
+    struct timeval   tmp_time;           /* used for time conversion */
+
     char             **updvals;
     int              schedule_smooth = 0;
        rrd_value_t      *seasonal_coef = NULL, *last_seasonal_coef = NULL;
@@ -203,6 +250,7 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
     enum cf_en       current_cf;
                                         /* numeric id of the current consolidation function */
     rpnstack_t       rpnstack; /* used for COMPUTE DS */
+    int                     version;  /* rrd version */
 
     rpnstack_init(&rpnstack);
 
@@ -211,10 +259,24 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
        rrd_set_error("Not enough arguments");
        return -1;
     }
+    
+    
 
     if(rrd_open(filename,&rrd_file,&rrd, RRD_READWRITE)==-1){
        return -1;
     }
+    /* initialize time */
+    version = atoi(rrd.stat_head->version);
+    gettimeofday(&tmp_time, 0);
+    normalize_time(&tmp_time);
+    current_time = tmp_time.tv_sec;
+    if(version >= 3) {
+        current_time_usec = tmp_time.tv_usec;
+    }
+    else {
+       current_time_usec = 0;
+    }
+
     rra_current = rra_start = rra_begin = ftell(rrd_file);
     /* This is defined in the ANSI C standard, section 7.9.5.3:
 
@@ -397,11 +459,22 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
            }
 
            current_time = mktime(&ds_tv.tm) + ds_tv.offset;
+           current_time_usec = 0; /* FIXME: how to handle usecs here ? */
+           
        } else if (strcmp(updvals[0],"N")==0){
-           current_time = time(NULL);
+           gettimeofday(&tmp_time, 0);
+           normalize_time(&tmp_time);
+           current_time = tmp_time.tv_sec;
+           current_time_usec = tmp_time.tv_usec;
        } else {
-           current_time = atol(updvals[0]);
+           double tmp;
+           tmp = strtod(updvals[0], 0);
+           current_time = floor(tmp);
+           current_time_usec = (long)((tmp - current_time) * 1000000L);
        }
+       /* dont do any correction for old version RRDs */
+       if(version < 3) 
+           current_time_usec = 0;
        
        if(current_time <= rrd.live_head->last_up){
            rrd_set_error("illegal attempt to update using time %ld when "
@@ -430,14 +503,17 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
        /* when did the last pdp_st occur */
        occu_pdp_age = current_time % rrd.stat_head->pdp_step;
        occu_pdp_st = current_time - occu_pdp_age;
-       interval = current_time - rrd.live_head->last_up;
+       /* interval = current_time - rrd.live_head->last_up; */
+       interval    = current_time + ((double)current_time_usec - (double)rrd.live_head->last_up_usec)/1000000.0 - rrd.live_head->last_up;
     
        if (occu_pdp_st > proc_pdp_st){
            /* OK we passed the pdp_st moment*/
            pre_int =  occu_pdp_st - rrd.live_head->last_up; /* how much of the input data
                                                              * occurred before the latest
                                                              * pdp_st moment*/
+           pre_int -= ((double)rrd.live_head->last_up_usec)/1000000.0; /* adjust usecs */
            post_int = occu_pdp_age;                         /* how much after it */
+           post_int += ((double)current_time_usec)/1000000.0;  /* adjust usecs */
        } else {
            pre_int = interval;
            post_int = 0;
@@ -449,9 +525,9 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
               "proc_pdp_st %lu\t" 
               "occu_pfp_age %lu\t" 
               "occu_pdp_st %lu\t"
-              "int %lu\t"
-              "pre_int %lu\t"
-              "post_int %lu\n", proc_pdp_age, proc_pdp_st, 
+              "int %lf\t"
+              "pre_int %lf\t"
+              "post_int %lf\n", proc_pdp_age, proc_pdp_st, 
                occu_pdp_age, occu_pdp_st,
               interval, pre_int, post_int);
 #endif
@@ -1075,6 +1151,7 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
            
        } /* endif a pdp_st has occurred */ 
        rrd.live_head->last_up = current_time;
+       rrd.live_head->last_up_usec = current_time_usec; 
        free(step_start);
     } /* function argument loop */
 
@@ -1112,17 +1189,33 @@ rrd_update_r(char *filename, char *template, int argc, char **argv)
        return(-1);
     }
 
-    if(fwrite( rrd.live_head,
-              sizeof(live_head_t), 1, rrd_file) != 1){
-       rrd_set_error("fwrite live_head to rrd");
-       free(updvals);
-       rrd_free(&rrd);
-       free(tmpl_idx);
-       free(pdp_temp);
-       free(pdp_new);
-       fclose(rrd_file);
-       return(-1);
+    if(version >= 3) {
+           if(fwrite( rrd.live_head,
+                      sizeof(live_head_t), 1, rrd_file) != 1){
+               rrd_set_error("fwrite live_head to rrd");
+               free(updvals);
+               rrd_free(&rrd);
+               free(tmpl_idx);
+               free(pdp_temp);
+               free(pdp_new);
+               fclose(rrd_file);
+               return(-1);
+           }
+    }
+    else {
+           if(fwrite( &rrd.live_head->last_up,
+                      sizeof(time_t), 1, rrd_file) != 1){
+               rrd_set_error("fwrite live_head to rrd");
+               free(updvals);
+               rrd_free(&rrd);
+               free(tmpl_idx);
+               free(pdp_temp);
+               free(pdp_new);
+               fclose(rrd_file);
+               return(-1);
+           }
     }
+           
 
     if(fwrite( rrd.pdp_prep,
               sizeof(pdp_prep_t),