]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/commitdiff
add rrd_modify (but do not yet use it)
authorPeter Stamfest <peter@stamfest.at>
Sun, 23 Feb 2014 22:15:39 +0000 (23:15 +0100)
committerPeter Stamfest <peter@stamfest.at>
Wed, 26 Feb 2014 10:25:30 +0000 (11:25 +0100)
src/Makefile.am
src/librrd.sym.in.in
src/rrd.h
src/rrd_modify.c [new file with mode: 0644]

index d4674a31846e19e34fe377ec1e6ca451f28adab0..79e3e1310f5170d1fe79156d17b2327cfd1a1c93 100644 (file)
@@ -45,7 +45,8 @@ RRD_C_FILES =         \
        rrd_flushcached.c \
        rrd_fetch.c     \
        rrd_resize.c \
-       rrd_tune.c
+       rrd_tune.c      \
+       rrd_modify.c
 
 if BUILD_RRDGRAPH
 RRD_C_FILES += rrd_graph.c     \
index dd31b6278f4dd8533561d1c26015e57273942d7c..ebc605b2cd8f88a4e375f19d97ffc86a87e115ea 100644 (file)
@@ -36,6 +36,7 @@ rrd_last_r
 rrd_lastupdate
 rrd_lastupdate_r
 rrd_lock
+rrd_modify
 rrd_mkdir_p
 rrd_new_context
 rrd_open
index 40b80cfe962d24c16b2130161dc0c9faf07d394c..0a1319bdd8a647e795db7712519dda72c1508778 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -194,6 +194,9 @@ extern    "C" {
     int       rrd_tune(
     int,
     char **);
+    int       rrd_modify(
+    int,
+    char **);
     time_t    rrd_last(
     int,
     char **);
diff --git a/src/rrd_modify.c b/src/rrd_modify.c
new file mode 100644 (file)
index 0000000..61ce464
--- /dev/null
@@ -0,0 +1,438 @@
+/*****************************************************************************
+ * RRDtool 1.4.8  Copyright by Tobi Oetiker, 1997-2013
+ *****************************************************************************
+ * rrd_modify  Structurally modify an RRD file
+ *****************************************************************************
+ * Initially based on rrd_dump.c
+ *****************************************************************************/
+#include "rrd_tool.h"
+#include "rrd_rpncalc.h"
+#include "rrd_client.h"
+#include "rrd_restore.h"   /* write_file */
+
+#include <locale.h>
+
+static void * copy_over_realloc(void *dest, int dest_index, 
+                               const void *src, int index,
+                               ssize_t size) {
+    void *r = realloc(dest, size * (dest_index + 1));
+    if (r == NULL) {
+        rrd_set_error("copy_over_realloc: realloc failed.");
+       return r;
+    }
+
+    memcpy(((char*)r) + size * dest_index, ((char*)src) + size * index, size);
+    return r;
+}
+
+static int rrd_modify_r(const char *infilename,
+                       const char *outfilename,
+                       const char **removeDS,
+                       const char **addDS) {
+    rrd_t in, out;
+    int rc = -1;
+    unsigned int i, j;
+    rrd_file_t *rrd_file;
+    char       *old_locale = "";
+    char *ops = NULL;
+
+    rrd_init(&in);
+    rrd_init(&out);
+
+    rrd_file = rrd_open(infilename, &in, RRD_READONLY | RRD_READAHEAD);
+    if (rrd_file == NULL) {
+       goto done;
+    }
+
+    /* copy over structure to out RRD */
+
+    out.stat_head = (stat_head_t *) malloc(sizeof(stat_head_t));
+    if (out.stat_head == NULL) {
+        rrd_set_error("rrd_modify_r: malloc failed.");
+       goto done;
+    }
+    
+    memset(out.stat_head, 0, (sizeof(stat_head_t)));
+
+    strncpy(out.stat_head->cookie, "RRD", sizeof(out.stat_head->cookie));
+    strcpy(out.stat_head->version, "0003");
+    out.stat_head->float_cookie = FLOAT_COOKIE;
+    out.stat_head->pdp_step = in.stat_head->pdp_step;
+
+    out.stat_head->ds_cnt = 0;
+    out.stat_head->rra_cnt = 0;
+
+    out.live_head = (live_head_t *) malloc(sizeof(live_head_t));
+    if (out.live_head == NULL) {
+        rrd_set_error("parse_tag_rrd: malloc failed.");
+       goto done;
+    }
+
+    out.live_head->last_up = in.live_head->last_up;
+    out.live_head->last_up_usec = in.live_head->last_up_usec;
+
+
+    ops = malloc(in.stat_head->ds_cnt);
+    if (ops == NULL) {
+        rrd_set_error("parse_tag_rrd: malloc failed.");
+       goto done;
+    } 
+
+    memset(ops, 'c', in.stat_head->ds_cnt);
+    
+    // check all DSs for deletion
+    for (i = 0 ; i < in.stat_head->ds_cnt ; i++) {
+       const char *c;
+       if (removeDS != NULL) {
+           for (j = 0, c = removeDS[j] ; c ; j++, c = removeDS[j]) {
+               if (strcmp(in.ds_def[i].ds_nam, c) == 0) {
+                   ops[i] = 'd';
+                   break;
+               }
+           }
+       }
+
+       if (ops[i] == 'c') {
+           j = out.stat_head->ds_cnt;
+           out.stat_head->ds_cnt++;
+
+           out.ds_def = copy_over_realloc(out.ds_def, j, 
+                                          in.ds_def, i,
+                                          sizeof(ds_def_t));
+           if (out.ds_def == NULL) goto done;
+
+           out.pdp_prep = copy_over_realloc(out.pdp_prep, j, 
+                                            in.pdp_prep, i,
+                                            sizeof(pdp_prep_t));
+           if (out.pdp_prep == NULL) goto done;
+
+       }
+    }
+
+    rra_ptr_t rra_0_ptr = { .cur_row = 0 };
+    for (j = 0 ; j < in.stat_head->rra_cnt ; j++) {
+
+       /* for every RRA copy only those CDPs in the prep area where we keep 
+          the DS! */
+
+       out.cdp_prep = realloc(out.cdp_prep, 
+                              sizeof(cdp_prep_t) * out.stat_head->ds_cnt 
+                              * (j+1));
+       int start_index_in  = in.stat_head->ds_cnt * j;
+       int start_index_out = out.stat_head->ds_cnt * j;
+       
+       int ii;
+       for (i = ii = 0 ; i < in.stat_head->ds_cnt ; i++) {
+           if (ops[i] == 'c') {
+               memcpy(out.cdp_prep + start_index_out + ii,
+                      in.cdp_prep + start_index_in + i, sizeof(cdp_prep_t));
+               ii++;
+           }
+       }
+
+
+
+       out.rra_def = copy_over_realloc(out.rra_def, j,
+                                       in.rra_def, j,
+                                       sizeof(rra_def_t));
+       if (out.rra_def == NULL) goto done;
+
+       out.rra_ptr = copy_over_realloc(out.rra_ptr, j,
+                                       &rra_0_ptr, 0,
+                                       sizeof(rra_ptr_t));
+       if (out.rra_ptr == NULL) goto done; 
+
+       //      out.rra_ptr[j].cur_row = out.rra_def[j].row_cnt - 1;
+
+       out.stat_head->rra_cnt++;
+    }
+
+    old_locale = setlocale(LC_NUMERIC, NULL);
+    setlocale(LC_NUMERIC, "C");
+
+    /* read all data ... */
+
+    /* there seem to be two function in the current rrdtool codebase
+       dealing with writing a new rrd file to disk: write_file and
+       rrd_create_fn.  The latter has the major problem, that it tries
+       to free data passed to it (WTF?), but write_file assumes
+       chronologically ordered data in RRAs (that is, in the data
+       space starting at rrd.rrd_value....
+
+       This is the reason why: 
+       - we use write_file and 
+       - why we reset cur_row in RRAs and reorder data to be cronological
+    */
+
+
+
+    char *all_data = NULL;
+    ssize_t total_size = 0, total_size_out = 0;
+    ssize_t rra_start = 0, rra_start_out = 0;
+
+    int total_cnt = 0, total_cnt_out = 0;
+
+    for (i = 0; i < in.stat_head->rra_cnt; i++) {
+       int rra_values     = in.stat_head->ds_cnt  * in.rra_def[i].row_cnt;
+       int rra_values_out = out.stat_head->ds_cnt * out.rra_def[i].row_cnt;
+
+       ssize_t rra_size     = sizeof(rrd_value_t) * rra_values;
+       ssize_t rra_size_out = sizeof(rrd_value_t) * rra_values_out;
+       /*
+       fprintf(stderr, "A %08x\n", &(in.rra_ptr[i]));
+       fprintf(stderr, "A %08x\n", in.rra_ptr[i].cur_row);
+       */
+       total_size += rra_size;
+       all_data = realloc(all_data, total_size);
+       in.rrd_value = (void *) all_data;
+
+       if (all_data == NULL) {
+           rrd_set_error("out of memory");
+           goto done;
+       }
+
+       total_size_out += rra_size_out;
+       out.rrd_value = realloc(out.rrd_value, total_size_out);
+
+       if (out.rrd_value == NULL) {
+           rrd_set_error("out of memory");
+           goto done;
+       }
+
+
+
+       /* reorder data by cleaverly reading it into the right place */
+
+       /*
+         Data in the RRD file:
+                                    
+         <-------------RRA-------------->
+         BBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAA
+          ^                    ^          ^
+          0                 cur_row    row_cnt
+
+         Data in memory should become
+                                    
+         <-------------RRA-------------->
+          AAAAAAAAAAABBBBBBBBBBBBBBBBBBBBB
+         ^          ^                    ^
+       cur_row=0     n                 row_cnt
+
+         using:   n = row_cnt - cur_row
+
+         we first read cur_row values to position n and then n values to 
+         position 0.
+
+        */
+
+       /* instead of the actual cur_row, we have to add 1, because
+          cur_row does not point to the next "free", but the
+          currently in use position */
+       int last = (in.rra_ptr[i].cur_row + 1) % in.rra_def[i].row_cnt; 
+       int n = in.rra_def[i].row_cnt - last;
+
+
+       size_t to_read = last * sizeof(rrd_value_t) * in.stat_head->ds_cnt;
+       size_t read_bytes;
+
+       if (to_read > 0) {
+           read_bytes = 
+               rrd_read(rrd_file, 
+                        all_data + rra_start + 
+                        n * sizeof(rrd_value_t) * in.stat_head->ds_cnt, 
+                        to_read);      
+           
+           if (read_bytes != to_read) {
+               rrd_set_error("short read 1");
+               goto done;
+           }
+       }
+       to_read = n * sizeof(rrd_value_t) * in.stat_head->ds_cnt ;
+       if (to_read > 0) {
+           read_bytes = 
+               rrd_read(rrd_file, 
+                        all_data + rra_start,
+                        to_read);
+           
+           if (read_bytes != to_read) {
+               rrd_set_error("short read 2");
+               goto done;
+           }
+       }
+
+       int ii, jj;
+       for (ii = 0 ; ii < in.rra_def[i].row_cnt ; ii++) {
+           for (j = jj = 0 ; j < in.stat_head->ds_cnt ; j++) {
+               if (ops[j] == 'c') {
+                   out.rrd_value[total_cnt_out +ii*out.stat_head->ds_cnt +jj] =
+                       in.rrd_value[total_cnt + ii * in.stat_head->ds_cnt + j];
+
+                   /*
+                   memcpy((void*) (out.rrd_value + total_cnt_out + ii * out.stat_head->ds_cnt + jj),
+                          (void*) (in.rrd_value + total_cnt + ii * in.stat_head->ds_cnt + j), sizeof(rrd_value_t));
+                   */                     
+                   /*
+                   fprintf(stderr, "%d->%d\n",
+                           total_cnt + ii * in.stat_head->ds_cnt + j,
+                           total_cnt_out + ii * out.stat_head->ds_cnt + jj);
+                   */
+                   jj++;
+               }
+           }
+       }
+
+       rra_start     += rra_size;
+       rra_start_out += rra_size_out;
+
+       total_cnt     += rra_values;
+       total_cnt_out += rra_values_out;
+    }
+/*
+    for (int z  = 0 ; z < 160 ; z++) {
+       fprintf(stderr, "%02x ", (unsigned) ((char*)all_data)[z] & 0x0ff);
+       if (z % 16 == 15) {
+           fprintf(stderr, "\n");
+       }
+    }
+
+
+    fprintf(stderr, "\n");
+    fprintf(stderr, "cnt %ld\n", (long) total_size);
+*/
+
+
+    write_file(outfilename, &out);
+
+    rc = 0;
+done:
+    if (rrd_file != NULL) {
+       rrd_close(rrd_file);
+    }
+    rrd_free(&in);
+    rrd_free(&out);
+
+    if (ops != NULL) free(ops);
+
+    return rc;
+}
+
+int rrd_modify (
+    int argc,
+    char **argv)
+{
+    int       rc;
+    int       i;
+    /** 
+     * 0 = no header
+     * 1 = dtd header
+     * 2 = xsd header
+     */
+    int       opt_header = 1;
+    char     *opt_daemon = NULL;
+
+    /* init rrd clean */
+
+    optind = 0;
+    opterr = 0;         /* initialize getopt */
+
+    while (42) {/* ha ha */
+        int       opt;
+        int       option_index = 0;
+        static struct option long_options[] = {
+            {"daemon", required_argument, 0, 'd'},
+            {0, 0, 0, 0}
+        };
+
+        opt = getopt_long(argc, argv, "d:", long_options, &option_index);
+
+        if (opt == EOF)
+            break;
+
+        switch (opt) {
+        case 'd':
+            if (opt_daemon != NULL)
+                    free (opt_daemon);
+            opt_daemon = strdup (optarg);
+            if (opt_daemon == NULL)
+            {
+                rrd_set_error ("strdup failed.");
+                return (-1);
+            }
+            break;
+
+        default:
+            rrd_set_error("usage rrdtool %s"
+                          "in.rrd out.rrd", argv[0]);
+            return (-1);
+            break;
+        }
+    }                   /* while (42) */
+
+    if ((argc - optind) < 2) {
+        rrd_set_error("usage rrdtool %s"
+                      "in.rrd out.rrd", argv[0]);
+        return (-1);
+    }
+
+    rc = rrdc_flush_if_daemon(opt_daemon, argv[optind]);
+    if (opt_daemon) free(opt_daemon);
+    if (rc) return (rc);
+
+    // parse add/remove options
+    char **remove = NULL, **add = NULL;
+    int rcnt = 0, acnt = 0;
+
+    for (i = optind + 2 ; i < argc ; i++) {
+       if (strncmp("DEL:", argv[i], 4) == 0 && strlen(argv[i]) > 4) {
+           remove = realloc(remove, (rcnt + 2) * sizeof(char*));
+           if (remove == NULL) {
+               rrd_set_error("out of memory");
+               return -1;
+           }
+
+           remove[rcnt] = strdup(argv[i] + 4);
+           if (remove[rcnt] == NULL) {
+               rrd_set_error("out of memory");
+               return -1;
+           }
+
+           rcnt++;
+           remove[rcnt] = NULL;
+       }
+       if (strncmp("DS:", argv[i], 3) == 0 && strlen(argv[i]) > 3) {
+           add = realloc(add, (acnt + 2) * sizeof(char*));
+           if (add == NULL) {
+               rrd_set_error("out of memory");
+               return -1;
+           }
+
+           add[acnt] = strdup(argv[i]);
+           if (add[acnt] == NULL) {
+               rrd_set_error("out of memory");
+               return -1;
+           }
+
+           acnt++;
+           add[acnt] = NULL;
+       }
+    }
+
+    if ((argc - optind) >= 2) {
+        rc = rrd_modify_r(argv[optind], argv[optind + 1], 
+                         remove, add);
+    }
+
+    if (remove) {
+       for (char **c = remove ; *c ; c++) {
+           free(*c);
+       }
+       free(remove);
+    } 
+    if (add) {
+       for (char **c = add ; *c ; c++) {
+           free(*c);
+       }
+       free(add);
+    }
+    return rc;
+}