prepare for the release of rrdtool-1.2.16
[rrdtool.git] / src / rrd_resize.c
1 /*****************************************************************************
2  * RRDtool 1.2.16  Copyright by Tobi Oetiker, 1997-2006
3  *****************************************************************************
4  * rrd_resize.c Alters size of an RRA
5  *****************************************************************************
6  * Initial version by Alex van den Bogaerdt
7  *****************************************************************************/
8
9 #include "rrd_tool.h"
10
11 int
12 rrd_resize(int argc, char **argv)
13 {
14     char                *infilename,outfilename[11]="resize.rrd";
15     FILE                *infile,*outfile;
16     rrd_t               rrdold,rrdnew;
17     rrd_value_t         buffer;
18     int                 version;
19     unsigned long       l,rra;
20     long                modify;
21     unsigned long       target_rra;
22     int                 grow=0,shrink=0;
23     char                *endptr;
24
25     infilename=argv[1];
26     if (!strcmp(infilename,"resize.rrd")) {
27         rrd_set_error("resize.rrd is a reserved name");
28         return(-1);
29     }
30     if (argc!=5) {
31         rrd_set_error("wrong number of parameters");
32         return(-1);
33     }
34
35     target_rra=strtol(argv[2],&endptr,0);
36
37     if (!strcmp(argv[3],"GROW")) grow=1;
38     else if (!strcmp(argv[3],"SHRINK")) shrink=1;
39     else {
40         rrd_set_error("I can only GROW or SHRINK");
41         return(-1);
42     }
43
44     modify=strtol(argv[4],&endptr,0);
45
46     if ((modify<1)) {
47         rrd_set_error("Please grow or shrink with at least 1 row");
48         return(-1);
49     }
50
51     if (shrink) modify = -modify;
52
53
54     if (rrd_open(infilename, &infile, &rrdold, RRD_READWRITE)==-1) {
55         rrd_set_error("could not open RRD");
56         return(-1);
57     }
58     if (LockRRD(infile) != 0) {
59         rrd_set_error("could not lock original RRD");
60         rrd_free(&rrdold);
61         fclose(infile);
62         return(-1);
63     }
64
65     if (target_rra >= rrdold.stat_head->rra_cnt) {
66         rrd_set_error("no such RRA in this RRD");
67         rrd_free(&rrdold);
68         fclose(infile);
69         return(-1);
70     }
71
72     if (modify < 0)
73         if ((long)rrdold.rra_def[target_rra].row_cnt <= -modify) {
74             rrd_set_error("This RRA is not that big");
75             rrd_free(&rrdold);
76             fclose(infile);
77             return(-1);
78         }
79
80     rrdnew.stat_head = rrdold.stat_head;
81     rrdnew.ds_def    = rrdold.ds_def;
82     rrdnew.rra_def   = rrdold.rra_def;
83     rrdnew.live_head = rrdold.live_head;
84     rrdnew.pdp_prep  = rrdold.pdp_prep;
85     rrdnew.cdp_prep  = rrdold.cdp_prep;
86     rrdnew.rra_ptr   = rrdold.rra_ptr;
87
88     version = atoi(rrdold.stat_head->version);
89     switch (version) {
90         case 3: break;
91         case 1: rrdold.stat_head->version[3]='3';
92                 break;
93         default: {
94                 rrd_set_error("Do not know how to handle RRD version %s",rrdold.stat_head->version);
95                 rrd_free(&rrdold);      
96                 fclose(infile);
97                 return(-1);
98                 }
99     }
100
101     if ((outfile=fopen(outfilename,"wb"))==NULL) {
102         rrd_set_error("Can't create '%s'",outfilename);
103         return(-1);
104     }
105     if (LockRRD(outfile) != 0) {
106         rrd_set_error("could not lock new RRD");
107         rrd_free(&rrdold);
108         fclose(infile);
109         fclose(outfile);
110         return(-1);
111     }
112     fwrite(rrdnew.stat_head, sizeof(stat_head_t),1,outfile);
113     fwrite(rrdnew.ds_def,sizeof(ds_def_t),rrdnew.stat_head->ds_cnt,outfile);
114     fwrite(rrdnew.rra_def,sizeof(rra_def_t),rrdnew.stat_head->rra_cnt,outfile);
115     fwrite(rrdnew.live_head,sizeof(live_head_t),1,outfile);
116     fwrite(rrdnew.pdp_prep,sizeof(pdp_prep_t),rrdnew.stat_head->ds_cnt,outfile);
117     fwrite(rrdnew.cdp_prep,sizeof(cdp_prep_t),rrdnew.stat_head->ds_cnt*rrdnew.stat_head->rra_cnt,outfile);
118     fwrite(rrdnew.rra_ptr,sizeof(rra_ptr_t),rrdnew.stat_head->rra_cnt,outfile);
119
120     /* Move the CDPs from the old to the new database.
121     ** This can be made (much) faster but isn't worth the effort. Clarity
122     ** is much more important.
123     */
124
125     /* Move data in unmodified RRAs
126     */
127     l=0;
128     for (rra=0;rra<target_rra;rra++) {
129         l+=rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt;
130     }
131     while (l>0) {
132         fread(&buffer,sizeof(rrd_value_t),1,infile);
133         fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
134         l--;
135     }
136     /* Move data in this RRA, either removing or adding some rows
137     */
138     if (modify>0) {
139         /* Adding extra rows; insert unknown values just after the
140         ** current row number.
141         */
142         l = rrdnew.stat_head->ds_cnt * (rrdnew.rra_ptr[target_rra].cur_row+1);
143         while (l>0) {
144             fread(&buffer,sizeof(rrd_value_t),1,infile);
145             fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
146             l--;
147         }
148         buffer=DNAN;
149         l=rrdnew.stat_head->ds_cnt * modify;
150         while (l>0) {
151             fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
152             l--;
153         }
154     } else {
155         /* Removing rows. Normally this would be just after the cursor
156         ** however this may also mean that we wrap to the beginning of
157         ** the array.
158         */
159         signed long int remove_end=0;
160
161         remove_end=(rrdnew.rra_ptr[target_rra].cur_row-modify)%rrdnew.rra_def[target_rra].row_cnt;
162         if (remove_end <= (signed long int)rrdnew.rra_ptr[target_rra].cur_row) {
163             while (remove_end >= 0) {
164                 fseek(infile,sizeof(rrd_value_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
165                 rrdnew.rra_ptr[target_rra].cur_row--;
166                 rrdnew.rra_def[target_rra].row_cnt--;
167                 remove_end--;
168                 modify++;
169             }
170             remove_end=rrdnew.rra_def[target_rra].row_cnt-1;
171         }
172         for (l=0;l<=rrdnew.rra_ptr[target_rra].cur_row;l++) {
173             unsigned int tmp;
174             for (tmp=0;tmp<rrdnew.stat_head->ds_cnt;tmp++) {
175                 fread(&buffer,sizeof(rrd_value_t),1,infile);
176                 fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
177             }
178         }
179         while (modify<0) {
180             fseek(infile,sizeof(rrd_value_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
181             rrdnew.rra_def[target_rra].row_cnt--;
182             modify++;
183         }
184     }
185     /* Move the rest of the CDPs
186     */
187     while (1) {
188         fread(&buffer,sizeof(rrd_value_t),1,infile);
189         if (feof(infile))
190             break;
191         fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
192     }
193     rrdnew.rra_def[target_rra].row_cnt += modify;
194     fseek(outfile,sizeof(stat_head_t)+sizeof(ds_def_t)*rrdnew.stat_head->ds_cnt,SEEK_SET);
195     fwrite(rrdnew.rra_def,sizeof(rra_def_t),rrdnew.stat_head->rra_cnt, outfile);
196     fseek(outfile,sizeof(live_head_t),SEEK_CUR);
197     fseek(outfile,sizeof(pdp_prep_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
198     fseek(outfile,sizeof(cdp_prep_t)*rrdnew.stat_head->ds_cnt*rrdnew.stat_head->rra_cnt,SEEK_CUR);
199     fwrite(rrdnew.rra_ptr,sizeof(rra_ptr_t),rrdnew.stat_head->rra_cnt, outfile);
200     
201     fclose(outfile);
202     rrd_free(&rrdold);
203     fclose(infile);
204     return(0);
205 }