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