b45e5db2465c849937bd902515e88711d507f886
[rrdtool.git] / src / rrd_tune.c
1 /*****************************************************************************
2  * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
3  *****************************************************************************
4  * change header parameters of an rrd
5  *****************************************************************************
6  * $Id$
7  * $Log$
8  * Revision 1.2  2001/03/04 13:01:55  oetiker
9  * Aberrant Behavior Detection support. A brief overview added to rrdtool.pod.
10  * Major updates to rrd_update.c, rrd_create.c. Minor update to other core files.
11  * This is backwards compatible! But new files using the Aberrant stuff are not readable
12  * by old rrdtool versions. See http://cricket.sourceforge.net/aberrant/rrd_hw.htm
13  * -- Jake Brutlag <jakeb@corp.webtv.net>
14  *
15  * Revision 1.1.1.1  2001/02/25 22:25:06  oetiker
16  * checkin
17  *
18  *****************************************************************************/
19
20 #include "rrd_tool.h"
21
22 int set_hwarg(rrd_t *rrd,enum cf_en cf,enum rra_par_en rra_par,char *arg);
23 int set_deltaarg(rrd_t *rrd,enum rra_par_en rra_par,char *arg);
24 int set_windowarg(rrd_t *rrd,enum rra_par_en,char *arg);
25
26 int
27 rrd_tune(int argc, char **argv)    
28 {   
29     rrd_t               rrd;
30     FILE               *rrd_file;
31     int                 matches;
32     int                 optcnt = 0;
33     long                ds;
34     char                ds_nam[DS_NAM_SIZE];
35     char                ds_new[DS_NAM_SIZE];
36     long                heartbeat;
37     double              min;
38     double              max;
39     char                dst[DST_SIZE];
40
41
42     if(rrd_open(argv[1],&rrd_file,&rrd, RRD_READWRITE)==-1){
43         return -1;
44     }
45
46     
47     while (1){
48         static struct option long_options[] =
49         {
50             {"heartbeat",        required_argument, 0, 'h'},
51             {"minimum",          required_argument, 0, 'i'},
52             {"maximum",          required_argument, 0, 'a'},
53             {"data-source-type", required_argument, 0, 'd'},
54             {"data-source-rename", required_argument, 0, 'r'},
55             /* added parameter tuning options for aberrant behavior detection */
56                 {"deltapos",required_argument,0,'p'},
57                 {"deltaneg",required_argument,0,'n'},
58                 {"window-length",required_argument,0,'w'},
59                 {"failure-threshold",required_argument,0,'f'},
60             {"alpha",required_argument,0,'x'},
61             {"beta",required_argument,0,'y'},
62             {"gamma",required_argument,0,'z'},
63             {0,0,0,0}
64         };
65         int option_index = 0;
66         int opt;
67         opt = getopt_long(argc, argv, "h:i:a:d:r:p:n:w:f:x:y:z:", 
68                           long_options, &option_index);
69         if (opt == EOF)
70             break;
71         
72         optcnt++;
73         switch(opt) {       
74         case 'h':
75             if ((matches = sscanf(optarg, DS_NAM_FMT ":%ld",ds_nam,&heartbeat)) != 2){
76                 rrd_set_error("invalid arguments for heartbeat");
77                 rrd_free(&rrd);
78                 fclose(rrd_file);
79                 return -1;
80             }
81             if ((ds=ds_match(&rrd,ds_nam))==-1){
82                 rrd_free(&rrd);
83                 fclose(rrd_file);
84                 return -1;
85             }
86             rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat;
87             break;
88
89         case 'i':
90             if ((matches = sscanf(optarg,DS_NAM_FMT ":%lf",ds_nam,&min)) <1){
91                 rrd_set_error("invalid arguments for minimum ds value");
92                 rrd_free(&rrd);
93                 fclose(rrd_file);
94                 return -1;
95             }
96             if ((ds=ds_match(&rrd,ds_nam))==-1){
97                 rrd_free(&rrd);
98                 fclose(rrd_file);
99                 return -1;
100             }
101
102             if(matches == 1)
103                 min= DNAN;
104             rrd.ds_def[ds].par[DS_min_val].u_val = min;
105             break;
106
107         case 'a':
108             if ((matches = sscanf(optarg, DS_NAM_FMT ":%lf",ds_nam,&max)) <1){
109                 rrd_set_error("invalid arguments for maximum ds value");
110                 rrd_free(&rrd);
111                 fclose(rrd_file);
112                 return -1;
113             }
114             if ((ds=ds_match(&rrd,ds_nam))==-1){
115                 rrd_free(&rrd);
116                 fclose(rrd_file);
117                 return -1;
118             }
119             if(matches == 1) 
120                 max= DNAN; 
121             rrd.ds_def[ds].par[DS_max_val].u_val = max;
122             break;
123
124         case 'd':
125             if ((matches = sscanf(optarg, DS_NAM_FMT ":" DST_FMT ,ds_nam,dst)) != 2){
126                 rrd_set_error("invalid arguments for data source type");
127                 rrd_free(&rrd);
128                 fclose(rrd_file);
129                 return -1;
130             }
131             if ((ds=ds_match(&rrd,ds_nam))==-1){
132                 rrd_free(&rrd);
133                 fclose(rrd_file);
134                 return -1;
135             }
136             if (dst_conv(dst) == -1){
137                 rrd_free(&rrd);
138                 fclose(rrd_file);
139                 return -1;
140             }
141             strncpy(rrd.ds_def[ds].dst,dst,DST_SIZE-1);
142             rrd.ds_def[ds].dst[DST_SIZE-1]='\0';
143
144             rrd.pdp_prep[ds].last_ds[0] = 'U';
145             rrd.pdp_prep[ds].last_ds[1] = 'N';
146             rrd.pdp_prep[ds].last_ds[2] = 'K';
147             rrd.pdp_prep[ds].last_ds[3] = 'N';
148             rrd.pdp_prep[ds].last_ds[4] = '\0';
149             
150             break;
151         case 'r':
152             if ((matches = 
153                  sscanf(optarg,DS_NAM_FMT ":" DS_NAM_FMT , ds_nam,ds_new)) != 2){
154                 rrd_set_error("invalid arguments for data source type");
155                 rrd_free(&rrd);
156                 fclose(rrd_file);
157                 return -1;
158             }
159             if ((ds=ds_match(&rrd,ds_nam))==-1){
160                 rrd_free(&rrd);
161                 fclose(rrd_file);
162                 return -1;
163             }
164             strncpy(rrd.ds_def[ds].ds_nam,ds_new,DS_NAM_SIZE-1);
165             rrd.ds_def[ds].ds_nam[DS_NAM_SIZE-1]='\0';
166             break;
167     case 'p':
168                 if (set_deltaarg(&rrd,RRA_delta_pos,optarg)) {
169                    rrd_free(&rrd);
170                    return -1;
171                 }
172                 break;
173         case 'n':
174                 if (set_deltaarg(&rrd,RRA_delta_neg,optarg)) {
175                    rrd_free(&rrd);
176                    return -1;
177                 }
178                 break;
179         case 'f':
180                 if (set_windowarg(&rrd,RRA_failure_threshold,optarg)) {
181                    rrd_free(&rrd);
182                    return -1;
183                 }
184                 break;
185         case 'w':
186                 if (set_windowarg(&rrd,RRA_window_len,optarg)) {
187                    rrd_free(&rrd);
188                    return -1;
189                 }
190                 break;
191         case 'x':
192                 if (set_hwarg(&rrd,CF_HWPREDICT,RRA_hw_alpha,optarg)) {
193                    rrd_free(&rrd);
194                    return -1;
195                 }
196                 break;
197         case 'y':
198                 if (set_hwarg(&rrd,CF_HWPREDICT,RRA_hw_beta,optarg)) {
199                    rrd_free(&rrd);
200                    return -1;
201                 }
202                 break;
203         case 'z':
204                 if (set_hwarg(&rrd,CF_SEASONAL,RRA_seasonal_gamma,optarg)) {
205                    rrd_free(&rrd);
206                    return -1;
207                 }
208                 break;
209         case '?':
210             if (optopt != 0)
211                 rrd_set_error("unknown option '%c'", optopt);
212             else
213                 rrd_set_error("unknown option '%s'",argv[optind-1]);
214             rrd_free(&rrd);         
215             fclose(rrd_file);
216             return -1;
217         }
218     }
219     if(optcnt>0){
220         
221         fseek(rrd_file,0,SEEK_SET);
222         fwrite(rrd.stat_head,
223                sizeof(stat_head_t),1, rrd_file);
224         fwrite(rrd.ds_def,
225                sizeof(ds_def_t), rrd.stat_head->ds_cnt, rrd_file);
226         /* need to write rra_defs for RRA parameter changes */
227         fwrite(rrd.rra_def, sizeof(rra_def_t), rrd.stat_head->rra_cnt,
228                    rrd_file);
229     } else {
230         int i;
231         for(i=0;i< rrd.stat_head->ds_cnt;i++)
232             printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n",
233                    rrd.ds_def[i].ds_nam,
234                    rrd.ds_def[i].dst,
235                    rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt,
236                    rrd.ds_def[i].par[DS_min_val].u_val,
237                    rrd.ds_def[i].par[DS_max_val].u_val);
238     }
239     fclose(rrd_file);
240     rrd_free(&rrd);
241     return 0;
242 }
243
244 int set_hwarg(rrd_t *rrd,enum cf_en cf,enum rra_par_en rra_par,char *arg)
245 {
246    double param;
247    unsigned long i;
248    signed short rra_idx = -1, devseasonal_idx = -1;
249    /* read the value */
250    param = atof(arg);
251    if (param <= 0.0 || param >= 1.0)
252    {
253           rrd_set_error("Holt-Winters parameter must be between 0 and 1");
254           return -1;
255    }
256    /* does the appropriate RRA exist?  */
257    for (i =  0; i < rrd -> stat_head -> rra_cnt; ++i)
258    {
259           if (cf_conv(rrd -> rra_def[i].cf_nam) == cf)
260           {
261                  rra_idx = i;
262           }
263           /* find the DEVSEASONAL index separately, as it is optional */
264           if (cf_conv(rrd -> rra_def[i].cf_nam) == CF_DEVSEASONAL)
265           {
266                  devseasonal_idx = i;
267           }
268    }
269    if (rra_idx == -1) 
270    {
271           rrd_set_error("Holt-Winters RRA does not exist in this RRD");
272           return -1;
273    }
274    
275    /* set the value */
276    rrd -> rra_def[rra_idx].par[rra_par].u_val = param;
277    if (devseasonal_idx > -1)
278           rrd -> rra_def[devseasonal_idx].par[rra_par].u_val = param;
279    return 0;
280 }
281
282 int set_deltaarg(rrd_t *rrd,enum rra_par_en rra_par,char *arg)
283 {
284    rrd_value_t param;
285    unsigned long i;
286    signed short rra_idx = -1;
287
288    param = atof(arg);
289    if (param < 0.1)
290    {
291           rrd_set_error("Parameter specified is too small");
292           return -1;
293    }
294    /* does the appropriate RRA exist?  */
295    for (i = 0; i < rrd -> stat_head -> rra_cnt; ++i)
296    {
297           if (cf_conv(rrd -> rra_def[i].cf_nam) == CF_FAILURES) 
298           {
299                  rra_idx = i;
300                  break;
301           }
302    }
303    if (rra_idx == -1) 
304    {
305           rrd_set_error("Failures RRA does not exist in this RRD");
306           return -1;
307    }
308
309    /* set the value */
310    rrd -> rra_def[rra_idx].par[rra_par].u_val = param;
311    return 0;
312 }
313
314 int set_windowarg(rrd_t *rrd,enum rra_par_en rra_par,char *arg)
315 {
316    unsigned long param;
317    unsigned long i, cdp_idx;
318    signed short rra_idx = -1;
319    /* read the value */
320    param = atoi(arg);
321    /* there are 4 chars to a long, reserve on CDP entry for future
322         * use. */
323    if (param < 1 || param > MAX_FAILURES_WINDOW_LEN)
324    {
325           rrd_set_error("Parameter must be between %d and %d",
326                  1, MAX_CDP_PAR_EN - 1);
327           return -1;
328    }
329    /* does the appropriate RRA exist?  */
330    for (i = 0; i < rrd -> stat_head -> rra_cnt; ++i)
331    {
332           if (cf_conv(rrd -> rra_def[i].cf_nam) == CF_FAILURES) 
333           {
334                  rra_idx = i;
335                  break;
336           }
337    }
338    if (rra_idx == -1) 
339    {
340           rrd_set_error("Failures RRA does not exist in this RRD");
341           return -1;
342    }
343    
344    /* set the value */
345    rrd -> rra_def[rra_idx].par[rra_par].u_cnt = param;
346
347    /* erase existing violations */
348    for (i = 0; i < rrd -> stat_head -> ds_cnt; i++)
349    {
350           cdp_idx = rra_idx * (rrd -> stat_head -> ds_cnt) + i;
351           erase_violations(rrd,cdp_idx,rra_idx);
352    }
353    return 0;
354 }