* progress in moving all the fileaccess over to a wrapper system that can do fd based...
[rrdtool.git] / src / rrd_resize.c
1 /*****************************************************************************
2  * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
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     rrd_t               rrdold,rrdnew;
16     rrd_value_t         buffer;
17     int                 version;
18     unsigned long       l,rra;
19     long                modify;
20     unsigned long       target_rra;
21     int                 grow=0,shrink=0;
22     char                *endptr;
23     rrd_file_t          *rrd_file, *rrd_out_file;
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     rrd_file = rrd_open(infilename, &rrdold, RRD_READWRITE);
55     if (rrd_file == NULL) {
56         rrd_set_error("could not open RRD");
57         return(-1);
58     }
59     if (LockRRD(rrd_file->fd) != 0) {
60         rrd_set_error("could not lock original RRD");
61         rrd_free(&rrdold);
62         close(rrd_file->fd);
63         return(-1);
64     }
65
66     if (target_rra >= rrdold.stat_head->rra_cnt) {
67         rrd_set_error("no such RRA in this RRD");
68         rrd_free(&rrdold);
69         close(rrd_file->fd);
70         return(-1);
71     }
72
73     if (modify < 0)
74         if ((long)rrdold.rra_def[target_rra].row_cnt <= -modify) {
75             rrd_set_error("This RRA is not that big");
76             rrd_free(&rrdold);
77             close(rrd_file->fd);
78             return(-1);
79         }
80
81     rrd_out_file = rrd_open(outfilename, &rrdnew, RRD_CREAT);
82     if (rrd_out_file == NULL) {
83         rrd_set_error("Can't create '%s': %s",outfilename, rrd_strerror(errno));
84         return(-1);
85     }
86     if (LockRRD(rrd_out_file->fd) != 0) {
87         rrd_set_error("could not lock new RRD");
88         rrd_free(&rrdold);
89         close(rrd_file->fd);
90         close(rrd_out_file->fd);
91         return(-1);
92     }
93 /*XXX: do one write for those parts of header that are unchanged */
94     rrdnew.stat_head = rrdold.stat_head;
95     rrdnew.ds_def    = rrdold.ds_def;
96     rrdnew.rra_def   = rrdold.rra_def;
97     rrdnew.live_head = rrdold.live_head;
98     rrdnew.pdp_prep  = rrdold.pdp_prep;
99     rrdnew.cdp_prep  = rrdold.cdp_prep;
100     rrdnew.rra_ptr   = rrdold.rra_ptr;
101
102     version = atoi(rrdold.stat_head->version);
103     switch (version) {
104         case 3: break;
105         case 1: rrdold.stat_head->version[3]='3';
106                 break;
107         default: {
108                 rrd_set_error("Do not know how to handle RRD version %s",rrdold.stat_head->version);
109                 rrd_free(&rrdold);      
110                 close(rrd_file->fd);
111                 return(-1);
112                 }
113     }
114
115
116 /* XXX: Error checking? */
117     rrd_write(rrd_out_file,rrdnew.stat_head, sizeof(stat_head_t)*1);
118     rrd_write(rrd_out_file,rrdnew.ds_def,sizeof(ds_def_t)*rrdnew.stat_head->ds_cnt);
119     rrd_write(rrd_out_file,rrdnew.rra_def,sizeof(rra_def_t)*rrdnew.stat_head->rra_cnt);
120     rrd_write(rrd_out_file,rrdnew.live_head,sizeof(live_head_t)*1);
121     rrd_write(rrd_out_file,rrdnew.pdp_prep,sizeof(pdp_prep_t)*rrdnew.stat_head->ds_cnt);
122     rrd_write(rrd_out_file,rrdnew.cdp_prep,sizeof(cdp_prep_t)*rrdnew.stat_head->ds_cnt*rrdnew.stat_head->rra_cnt);
123     rrd_write(rrd_out_file,rrdnew.rra_ptr,sizeof(rra_ptr_t)*rrdnew.stat_head->rra_cnt);
124
125     /* Move the CDPs from the old to the new database.
126     ** This can be made (much) faster but isn't worth the effort. Clarity
127     ** is much more important.
128     */
129
130     /* Move data in unmodified RRAs
131     */
132     l=0;
133     for (rra=0;rra<target_rra;rra++) {
134         l+=rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt;
135     }
136     while (l>0) {
137         rrd_read(rrd_file,&buffer,sizeof(rrd_value_t)*1);
138         rrd_write(rrd_out_file,&buffer,sizeof(rrd_value_t)*1);
139         l--;
140     }
141     /* Move data in this RRA, either removing or adding some rows
142     */
143     if (modify>0) {
144         /* Adding extra rows; insert unknown values just after the
145         ** current row number.
146         */
147         l = rrdnew.stat_head->ds_cnt * (rrdnew.rra_ptr[target_rra].cur_row+1);
148         while (l>0) {
149             rrd_read(rrd_file,&buffer,sizeof(rrd_value_t)*1);
150             rrd_write(rrd_out_file,&buffer,sizeof(rrd_value_t)*1);
151             l--;
152         }
153         buffer=DNAN;
154         l=rrdnew.stat_head->ds_cnt * modify;
155         while (l>0) {
156             rrd_write(rrd_out_file,&buffer,sizeof(rrd_value_t)*1);
157             l--;
158         }
159     } else {
160         /* Removing rows. Normally this would be just after the cursor
161         ** however this may also mean that we wrap to the beginning of
162         ** the array.
163         */
164         signed long int remove_end=0;
165
166         remove_end=(rrdnew.rra_ptr[target_rra].cur_row-modify)%rrdnew.rra_def[target_rra].row_cnt;
167         if (remove_end <= (signed long int)rrdnew.rra_ptr[target_rra].cur_row) {
168             while (remove_end >= 0) {
169                 rrd_seek(rrd_file,sizeof(rrd_value_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
170                 rrdnew.rra_ptr[target_rra].cur_row--;
171                 rrdnew.rra_def[target_rra].row_cnt--;
172                 remove_end--;
173                 modify++;
174             }
175             remove_end=rrdnew.rra_def[target_rra].row_cnt-1;
176         }
177         for (l=0;l<=rrdnew.rra_ptr[target_rra].cur_row;l++) {
178             unsigned int tmp;
179             for (tmp=0;tmp<rrdnew.stat_head->ds_cnt;tmp++) {
180                 rrd_read(rrd_file,&buffer,sizeof(rrd_value_t)*1);
181                 rrd_write(rrd_out_file,&buffer,sizeof(rrd_value_t)*1);
182             }
183         }
184         while (modify<0) {
185             rrd_seek(rrd_file,sizeof(rrd_value_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
186             rrdnew.rra_def[target_rra].row_cnt--;
187             modify++;
188         }
189     }
190     /* Move the rest of the CDPs
191     */
192     while (1) {
193         if (rrd_read(rrd_file,&buffer,sizeof(rrd_value_t)*1) <= 0)
194             break;
195         rrd_write(rrd_out_file,&buffer,sizeof(rrd_value_t)*1);
196     }
197     rrdnew.rra_def[target_rra].row_cnt += modify;
198     rrd_seek(rrd_out_file,sizeof(stat_head_t)+sizeof(ds_def_t)*rrdnew.stat_head->ds_cnt,SEEK_SET);
199     rrd_write(rrd_out_file,rrdnew.rra_def,sizeof(rra_def_t)*rrdnew.stat_head->rra_cnt);
200     rrd_seek(rrd_out_file,sizeof(live_head_t),SEEK_CUR);
201     rrd_seek(rrd_out_file,sizeof(pdp_prep_t)*rrdnew.stat_head->ds_cnt,SEEK_CUR);
202     rrd_seek(rrd_out_file,sizeof(cdp_prep_t)*rrdnew.stat_head->ds_cnt*rrdnew.stat_head->rra_cnt,SEEK_CUR);
203     rrd_write(rrd_out_file,rrdnew.rra_ptr,sizeof(rra_ptr_t)*rrdnew.stat_head->rra_cnt);
204
205     close(rrd_out_file->fd);
206     rrd_free(&rrdold);
207     close(rrd_file->fd);
208     return(0);
209 }