with MMAP enabled rrd resize GROW was broken ... this fixes it ...
[rrdtool.git] / src / rrd_resize.c
index 0f4ceaa..2dc47b0 100644 (file)
 /*****************************************************************************
- * RRDtool 1.2.13  Copyright by Tobi Oetiker, 1997-2006
+ * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2008
  *****************************************************************************
  * rrd_resize.c Alters size of an RRA
  *****************************************************************************
  * Initial version by Alex van den Bogaerdt
  *****************************************************************************/
 
+#include <stdlib.h>
+
 #include "rrd_tool.h"
 
-int
-rrd_resize(int argc, char **argv)
+int rrd_resize(
+    int argc,
+    char **argv)
 {
-    char               *infilename,outfilename[11]="resize.rrd";
-    FILE               *infile,*outfile;
-    rrd_t              rrdold,rrdnew;
-    rrd_value_t                buffer;
-    int                        version;
-    unsigned long      l,rra;
-    long               modify;
-    unsigned long      target_rra;
-    int                        grow=0,shrink=0;
-    char               *endptr;
-
-    infilename=argv[1];
-    if (!strcmp(infilename,"resize.rrd")) {
+    char     *infilename, outfilename[11] = "resize.rrd";
+    rrd_t     rrdold, rrdnew;
+    rrd_value_t buffer;
+    int       version;
+    unsigned long l, rra;
+    long      modify;
+    unsigned long target_rra;
+    int       grow = 0, shrink = 0;
+    char     *endptr;
+    rrd_file_t *rrd_file, *rrd_out_file;
+
+    infilename = argv[1];
+    if (!strcmp(infilename, "resize.rrd")) {
         rrd_set_error("resize.rrd is a reserved name");
-        return(-1);
+        return (-1);
     }
-    if (argc!=5) {
+    if (argc != 5) {
         rrd_set_error("wrong number of parameters");
-        return(-1);
+        return (-1);
     }
 
-    target_rra=strtol(argv[2],&endptr,0);
+    target_rra = strtol(argv[2], &endptr, 0);
 
-    if (!strcmp(argv[3],"GROW")) grow=1;
-    else if (!strcmp(argv[3],"SHRINK")) shrink=1;
+    if (!strcmp(argv[3], "GROW"))
+        grow = 1;
+    else if (!strcmp(argv[3], "SHRINK"))
+        shrink = 1;
     else {
         rrd_set_error("I can only GROW or SHRINK");
-        return(-1);
+        return (-1);
     }
 
-    modify=strtol(argv[4],&endptr,0);
+    modify = strtol(argv[4], &endptr, 0);
 
-    if ((modify<1)) {
+    if ((modify < 1)) {
         rrd_set_error("Please grow or shrink with at least 1 row");
-        return(-1);
+        return (-1);
     }
 
-    if (shrink) modify = -modify;
+    if (shrink)
+        modify = -modify;
 
 
-    if (rrd_open(infilename, &infile, &rrdold, RRD_READWRITE)==-1) {
-        rrd_set_error("could not open RRD");
-        return(-1);
+    rrd_init(&rrdold);
+    rrd_file = rrd_open(infilename, &rrdold, RRD_READWRITE | RRD_COPY);
+    if (rrd_file == NULL) {
+        rrd_free(&rrdold);
+        return (-1);
     }
-    if (LockRRD(infile) != 0) {
+
+    if (rrd_lock(rrd_file) != 0) {
         rrd_set_error("could not lock original RRD");
         rrd_free(&rrdold);
-        fclose(infile);
-        return(-1);
+        rrd_close(rrd_file);
+        return (-1);
     }
 
+
     if (target_rra >= rrdold.stat_head->rra_cnt) {
         rrd_set_error("no such RRA in this RRD");
         rrd_free(&rrdold);
-        fclose(infile);
-        return(-1);
+        rrd_close(rrd_file);
+        return (-1);
     }
 
     if (modify < 0)
-       if ((long)rrdold.rra_def[target_rra].row_cnt <= -modify) {
-           rrd_set_error("This RRA is not that big");
-           rrd_free(&rrdold);
-           fclose(infile);
-           return(-1);
-       }
-
-    rrdnew.stat_head = rrdold.stat_head;
-    rrdnew.ds_def    = rrdold.ds_def;
-    rrdnew.rra_def   = rrdold.rra_def;
+        if ((long) rrdold.rra_def[target_rra].row_cnt <= -modify) {
+            rrd_set_error("This RRA is not that big");
+            rrd_free(&rrdold);
+            rrd_close(rrd_file);
+            return (-1);
+        }
+
+    rrd_init(&rrdnew);
+    /* These need to be initialised before calling rrd_open() with 
+       the RRD_CREATE flag */
+
+    if ((rrdnew.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
+        rrd_set_error("allocating stat_head for new RRD");
+        rrd_free(&rrdold);
+        rrd_close(rrd_file);
+        return (-1);
+    }
+    memcpy(rrdnew.stat_head,rrdold.stat_head,sizeof(stat_head_t));
+
+    if ((rrdnew.rra_def = (rra_def_t *)malloc(sizeof(rra_def_t) * rrdold.stat_head->rra_cnt)) == NULL) {
+        rrd_set_error("allocating rra_def for new RRD");
+        rrd_free(&rrdnew);
+        rrd_free(&rrdold);
+        rrd_close(rrd_file);
+        return (-1);
+    }
+    memcpy(rrdnew.rra_def,rrdold.rra_def,sizeof(rra_def_t) * rrdold.stat_head->rra_cnt);
+
+    /* Set this so that the file will be created with the correct size */
+    rrdnew.rra_def[target_rra].row_cnt += modify;
+
+    rrd_out_file = rrd_open(outfilename, &rrdnew, RRD_READWRITE | RRD_CREAT);
+    if (rrd_out_file == NULL) {
+        rrd_set_error("Can't create '%s': %s", outfilename,
+                      rrd_strerror(errno));
+        rrd_free(&rrdnew);
+        rrd_free(&rrdold);
+        rrd_close(rrd_file);
+        rrd_close(rrd_out_file);
+        return (-1);
+    }
+    if (rrd_lock(rrd_out_file) != 0) {
+        rrd_set_error("could not lock new RRD");
+        rrd_free(&rrdnew);
+        rrd_free(&rrdold);
+        rrd_close(rrd_file);
+        rrd_close(rrd_out_file);
+        return (-1);
+    }
+/*XXX: do one write for those parts of header that are unchanged */
+    if ((rrdnew.rra_ptr = (rra_ptr_t *)malloc(sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt)) == NULL) {
+        rrd_set_error("allocating rra_ptr for new RRD");
+        rrd_free(&rrdnew);
+        rrd_free(&rrdold);
+        rrd_close(rrd_file);
+        rrd_close(rrd_out_file);
+        return (-1);
+    }
+
+    /* Put this back the way it was so that the rest of the algorithm
+       below remains unchanged, it will be corrected later */
+    rrdnew.rra_def[target_rra].row_cnt -= modify;
+
+    rrdnew.ds_def = rrdold.ds_def;
     rrdnew.live_head = rrdold.live_head;
-    rrdnew.pdp_prep  = rrdold.pdp_prep;
-    rrdnew.cdp_prep  = rrdold.cdp_prep;
-    rrdnew.rra_ptr   = rrdold.rra_ptr;
+    rrdnew.pdp_prep = rrdold.pdp_prep;
+    rrdnew.cdp_prep = rrdold.cdp_prep;
+    memcpy(rrdnew.rra_ptr,rrdold.rra_ptr,sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt);
+
 
     version = atoi(rrdold.stat_head->version);
     switch (version) {
-       case 3: break;
-       case 1: rrdold.stat_head->version[3]='3';
-               break;
-       default: {
-               rrd_set_error("Do not know how to handle RRD version %s",rrdold.stat_head->version);
-               rrd_free(&rrdold);      
-               fclose(infile);
-               return(-1);
-               }
-    }
-
-    if ((outfile=fopen(outfilename,"wb"))==NULL) {
-        rrd_set_error("Can't create '%s'",outfilename);
-        return(-1);
-    }
-    if (LockRRD(outfile) != 0) {
-        rrd_set_error("could not lock new RRD");
+    case 4:
+        break;        
+    case 3:
+        break;
+    case 1:
+        rrdnew.stat_head->version[3] = '3';
+        break;
+    default:
+        rrd_set_error("Do not know how to handle RRD version %s",
+                      rrdold.stat_head->version);
+        rrd_free(&rrdnew);
         rrd_free(&rrdold);
-        fclose(infile);
-        fclose(outfile);
-        return(-1);
-    }
-    fwrite(rrdnew.stat_head, sizeof(stat_head_t),1,outfile);
-    fwrite(rrdnew.ds_def,sizeof(ds_def_t),rrdnew.stat_head->ds_cnt,outfile);
-    fwrite(rrdnew.rra_def,sizeof(rra_def_t),rrdnew.stat_head->rra_cnt,outfile);
-    fwrite(rrdnew.live_head,sizeof(live_head_t),1,outfile);
-    fwrite(rrdnew.pdp_prep,sizeof(pdp_prep_t),rrdnew.stat_head->ds_cnt,outfile);
-    fwrite(rrdnew.cdp_prep,sizeof(cdp_prep_t),rrdnew.stat_head->ds_cnt*rrdnew.stat_head->rra_cnt,outfile);
-    fwrite(rrdnew.rra_ptr,sizeof(rra_ptr_t),rrdnew.stat_head->rra_cnt,outfile);
+        rrd_close(rrd_file);
+        rrd_close(rrd_out_file);
+        return (-1);
+        break;
+    }
+
+/* XXX: Error checking? */
+    rrd_write(rrd_out_file, rrdnew.stat_head, sizeof(stat_head_t) * 1);
+    rrd_write(rrd_out_file, rrdnew.ds_def,
+              sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt);
+    rrd_write(rrd_out_file, rrdnew.rra_def,
+              sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt);
+    rrd_write(rrd_out_file, rrdnew.live_head, sizeof(live_head_t) * 1);
+    rrd_write(rrd_out_file, rrdnew.pdp_prep,
+              sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt);
+    rrd_write(rrd_out_file, rrdnew.cdp_prep,
+              sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt *
+              rrdnew.stat_head->rra_cnt);
+    rrd_write(rrd_out_file, rrdnew.rra_ptr,
+              sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt);
 
     /* Move the CDPs from the old to the new database.
-    ** This can be made (much) faster but isn't worth the effort. Clarity
-    ** is much more important.
-    */
+     ** This can be made (much) faster but isn't worth the effort. Clarity
+     ** is much more important.
+     */
 
     /* Move data in unmodified RRAs
-    */
-    l=0;
-    for (rra=0;rra<target_rra;rra++) {
-        l+=rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt;
-    }
-    while (l>0) {
-        fread(&buffer,sizeof(rrd_value_t),1,infile);
-        fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
+     */
+    l = 0;
+    for (rra = 0; rra < target_rra; rra++) {
+        l += rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt;
+    }
+    while (l > 0) {
+        rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1);
+        rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
         l--;
     }
     /* Move data in this RRA, either removing or adding some rows
-    */
-    if (modify>0) {
+     */
+    if (modify > 0) {
         /* Adding extra rows; insert unknown values just after the
-        ** current row number.
-        */
-        l = rrdnew.stat_head->ds_cnt * (rrdnew.rra_ptr[target_rra].cur_row+1);
-        while (l>0) {
-            fread(&buffer,sizeof(rrd_value_t),1,infile);
-            fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
+         ** current row number.
+         */
+        l = rrdnew.stat_head->ds_cnt *
+            (rrdnew.rra_ptr[target_rra].cur_row + 1);
+        while (l > 0) {
+            rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1);
+            rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
             l--;
         }
-        buffer=DNAN;
-        l=rrdnew.stat_head->ds_cnt * modify;
-        while (l>0) {
-            fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
+        buffer = DNAN;
+        l = rrdnew.stat_head->ds_cnt * modify;
+        while (l > 0) {
+            rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
             l--;
         }
     } else {
         /* Removing rows. Normally this would be just after the cursor
-        ** however this may also mean that we wrap to the beginning of
-        ** the array.
-        */
-        signed long int remove_end=0;
+         ** however this may also mean that we wrap to the beginning of
+         ** the array.
+         */
+        signed long int remove_end = 0;
 
-        remove_end=(rrdnew.rra_ptr[target_rra].cur_row-modify)%rrdnew.rra_def[target_rra].row_cnt;
-        if (remove_end <= (signed long int)rrdnew.rra_ptr[target_rra].cur_row) {
+        remove_end =
+            (rrdnew.rra_ptr[target_rra].cur_row -
+             modify) % rrdnew.rra_def[target_rra].row_cnt;
+        if (remove_end <=
+            (signed long int) rrdnew.rra_ptr[target_rra].cur_row) {
             while (remove_end >= 0) {
-                fseek(infile,sizeof(rrd_value_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
+                rrd_seek(rrd_file,
+                         sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt,
+                         SEEK_CUR);
                 rrdnew.rra_ptr[target_rra].cur_row--;
                 rrdnew.rra_def[target_rra].row_cnt--;
                 remove_end--;
                 modify++;
             }
-            remove_end=rrdnew.rra_def[target_rra].row_cnt-1;
+            remove_end = rrdnew.rra_def[target_rra].row_cnt - 1;
         }
-        for (l=0;l<=rrdnew.rra_ptr[target_rra].cur_row;l++) {
+        for (l = 0; l <= rrdnew.rra_ptr[target_rra].cur_row; l++) {
             unsigned int tmp;
-            for (tmp=0;tmp<rrdnew.stat_head->ds_cnt;tmp++) {
-                fread(&buffer,sizeof(rrd_value_t),1,infile);
-                fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
+
+            for (tmp = 0; tmp < rrdnew.stat_head->ds_cnt; tmp++) {
+                rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1);
+                rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
             }
         }
-        while (modify<0) {
-            fseek(infile,sizeof(rrd_value_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
+        while (modify < 0) {
+            rrd_seek(rrd_file,
+                     sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt,
+                     SEEK_CUR);
             rrdnew.rra_def[target_rra].row_cnt--;
             modify++;
         }
     }
     /* Move the rest of the CDPs
-    */
+     */
     while (1) {
-       fread(&buffer,sizeof(rrd_value_t),1,infile);
-       if (feof(infile))
-           break;
-        fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
+        if (rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1) <= 0)
+            break;
+        rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1);
     }
     rrdnew.rra_def[target_rra].row_cnt += modify;
-    fseek(outfile,sizeof(stat_head_t)+sizeof(ds_def_t)*rrdnew.stat_head->ds_cnt,SEEK_SET);
-    fwrite(rrdnew.rra_def,sizeof(rra_def_t),rrdnew.stat_head->rra_cnt, outfile);
-    fseek(outfile,sizeof(live_head_t),SEEK_CUR);
-    fseek(outfile,sizeof(pdp_prep_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
-    fseek(outfile,sizeof(cdp_prep_t)*rrdnew.stat_head->ds_cnt*rrdnew.stat_head->rra_cnt,SEEK_CUR);
-    fwrite(rrdnew.rra_ptr,sizeof(rra_ptr_t),rrdnew.stat_head->rra_cnt, outfile);
-    
-    fclose(outfile);
+    rrd_seek(rrd_out_file,
+             sizeof(stat_head_t) +
+             sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt, SEEK_SET);
+    rrd_write(rrd_out_file, rrdnew.rra_def,
+              sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt);
+    rrd_seek(rrd_out_file, sizeof(live_head_t), SEEK_CUR);
+    rrd_seek(rrd_out_file, sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt,
+             SEEK_CUR);
+    rrd_seek(rrd_out_file,
+             sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt *
+             rrdnew.stat_head->rra_cnt, SEEK_CUR);
+    rrd_write(rrd_out_file, rrdnew.rra_ptr,
+              sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt);
+    rrd_close(rrd_file);    
+    rrd_close(rrd_out_file);    
     rrd_free(&rrdold);
-    fclose(infile);
-    return(0);
+    rrd_free(&rrdnew);
+    return (0);
 }