9a971cc4777560024b65558f916188b296df579c
[rrdtool.git] / src / rrd_create.c
1 /*****************************************************************************
2  * RRDtool 1.4.2  Copyright by Tobi Oetiker, 1997-2009
3  *****************************************************************************
4  * rrd_create.c  creates new rrds
5  *****************************************************************************/
6
7 #include <stdlib.h>
8 #include <time.h>
9 #include <locale.h>
10
11 #include "rrd_tool.h"
12 #include "rrd_rpncalc.h"
13 #include "rrd_hw.h"
14
15 #include "rrd_is_thread_safe.h"
16
17 #ifdef WIN32
18 # include <process.h>
19 #endif
20
21 unsigned long FnvHash(
22     const char *str);
23 int       create_hw_contingent_rras(
24     rrd_t *rrd,
25     unsigned short period,
26     unsigned long hashed_name);
27 void      parseGENERIC_DS(
28     const char *def,
29     rrd_t *rrd,
30     int ds_idx);
31
32 static void rrd_free2(
33     rrd_t *rrd);        /* our onwn copy, immmune to mmap */
34
35 int rrd_create(
36     int argc,
37     char **argv)
38 {
39     struct option long_options[] = {
40         {"start", required_argument, 0, 'b'},
41         {"step", required_argument, 0, 's'},
42         {0, 0, 0, 0}
43     };
44     int       option_index = 0;
45     int       opt;
46     time_t    last_up = time(NULL) - 10;
47     unsigned long pdp_step = 300;
48     rrd_time_value_t last_up_tv;
49     char     *parsetime_error = NULL;
50     long      long_tmp;
51     int       rc;
52
53     optind = 0;
54     opterr = 0;         /* initialize getopt */
55
56     while (1) {
57         opt = getopt_long(argc, argv, "b:s:", long_options, &option_index);
58
59         if (opt == EOF)
60             break;
61
62         switch (opt) {
63         case 'b':
64             if ((parsetime_error = rrd_parsetime(optarg, &last_up_tv))) {
65                 rrd_set_error("start time: %s", parsetime_error);
66                 return (-1);
67             }
68             if (last_up_tv.type == RELATIVE_TO_END_TIME ||
69                 last_up_tv.type == RELATIVE_TO_START_TIME) {
70                 rrd_set_error("specifying time relative to the 'start' "
71                               "or 'end' makes no sense here");
72                 return (-1);
73             }
74
75             last_up = mktime(&last_up_tv.tm) +last_up_tv.offset;
76
77             if (last_up < 3600 * 24 * 365 * 10) {
78                 rrd_set_error
79                     ("the first entry to the RRD should be after 1980");
80                 return (-1);
81             }
82             break;
83
84         case 's':
85             long_tmp = atol(optarg);
86             if (long_tmp < 1) {
87                 rrd_set_error("step size should be no less than one second");
88                 return (-1);
89             }
90             pdp_step = long_tmp;
91             break;
92
93         case '?':
94             if (optopt != 0)
95                 rrd_set_error("unknown option '%c'", optopt);
96             else
97                 rrd_set_error("unknown option '%s'", argv[optind - 1]);
98             return (-1);
99         }
100     }
101     if (optind == argc) {
102         rrd_set_error("need name of an rrd file to create");
103         return -1;
104     }
105     rc = rrd_create_r(argv[optind],
106                       pdp_step, last_up,
107                       argc - optind - 1, (const char **) (argv + optind + 1));
108
109     return rc;
110 }
111
112 /* #define DEBUG */
113 int rrd_create_r(
114     const char *filename,
115     unsigned long pdp_step,
116     time_t last_up,
117     int argc,
118     const char **argv)
119 {
120     rrd_t     rrd;
121     long      i;
122     int       offset;
123     char     *token;
124     char      dummychar1[2], dummychar2[2];
125     unsigned short token_idx, error_flag, period = 0;
126     unsigned long hashed_name;
127
128     /* init rrd clean */
129     rrd_init(&rrd);
130     /* static header */
131     if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
132         rrd_set_error("allocating rrd.stat_head");
133         rrd_free2(&rrd);
134         return (-1);
135     }
136
137     /* live header */
138     if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) {
139         rrd_set_error("allocating rrd.live_head");
140         rrd_free2(&rrd);
141         return (-1);
142     }
143
144     /* set some defaults */
145     strcpy(rrd.stat_head->cookie, RRD_COOKIE);
146     strcpy(rrd.stat_head->version, RRD_VERSION3);   /* by default we are still version 3 */
147     rrd.stat_head->float_cookie = FLOAT_COOKIE;
148     rrd.stat_head->ds_cnt = 0;  /* this will be adjusted later */
149     rrd.stat_head->rra_cnt = 0; /* ditto */
150     rrd.stat_head->pdp_step = pdp_step; /* 5 minute default */
151
152     /* a default value */
153     rrd.ds_def = NULL;
154     rrd.rra_def = NULL;
155
156     rrd.live_head->last_up = last_up;
157
158     /* optind points to the first non-option command line arg,
159      * in this case, the file name. */
160     /* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL
161      * arrays. */
162     hashed_name = FnvHash(filename);
163     for (i = 0; i < argc; i++) {
164         unsigned int ii;
165
166         if (strncmp(argv[i], "DS:", 3) == 0) {
167             size_t    old_size = sizeof(ds_def_t) * (rrd.stat_head->ds_cnt);
168
169             if ((rrd.ds_def = (ds_def_t*)rrd_realloc(rrd.ds_def,
170                                           old_size + sizeof(ds_def_t))) ==
171                 NULL) {
172                 rrd_set_error("allocating rrd.ds_def");
173                 rrd_free2(&rrd);
174                 return (-1);
175             }
176             memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
177             /* extract the name and type */
178             switch (sscanf(&argv[i][3],
179                            DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
180                            rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
181                            dummychar1,
182                            rrd.ds_def[rrd.stat_head->ds_cnt].dst,
183                            dummychar2, &offset)) {
184             case 0:
185             case 1:
186                 rrd_set_error("Invalid DS name");
187                 break;
188             case 2:
189             case 3:
190                 rrd_set_error("Invalid DS type");
191                 break;
192             case 4:    /* (%n may or may not be counted) */
193             case 5:    /* check for duplicate datasource names */
194                 for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++)
195                     if (strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
196                                rrd.ds_def[ii].ds_nam) == 0)
197                         rrd_set_error("Duplicate DS name: %s",
198                                       rrd.ds_def[ii].ds_nam);
199                 /* DS_type may be valid or not. Checked later */
200                 break;
201             default:
202                 rrd_set_error("invalid DS format");
203             }
204             if (rrd_test_error()) {
205                 rrd_free2(&rrd);
206                 return -1;
207             }
208
209             /* parse the remainder of the arguments */
210             switch (dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst)) {
211             case DST_COUNTER:
212             case DST_ABSOLUTE:
213             case DST_GAUGE:
214             case DST_DERIVE:
215                 parseGENERIC_DS(&argv[i][offset + 3], &rrd,
216                                 rrd.stat_head->ds_cnt);
217                 break;
218             case DST_CDEF:
219                 parseCDEF_DS(&argv[i][offset + 3], &rrd,
220                              rrd.stat_head->ds_cnt);
221                 break;
222             default:
223                 rrd_set_error("invalid DS type specified");
224                 break;
225             }
226
227             if (rrd_test_error()) {
228                 rrd_free2(&rrd);
229                 return -1;
230             }
231             rrd.stat_head->ds_cnt++;
232         } else if (strncmp(argv[i], "RRA:", 4) == 0) {
233             char     *argvcopy;
234             char     *tokptr = "";
235             size_t    old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt);
236             int       row_cnt;
237
238             if ((rrd.rra_def = (rra_def_t*)rrd_realloc(rrd.rra_def,
239                                            old_size + sizeof(rra_def_t))) ==
240                 NULL) {
241                 rrd_set_error("allocating rrd.rra_def");
242                 rrd_free2(&rrd);
243                 return (-1);
244             }
245             memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0,
246                    sizeof(rra_def_t));
247
248             argvcopy = strdup(argv[i]);
249             token = strtok_r(&argvcopy[4], ":", &tokptr);
250             token_idx = error_flag = 0;
251             while (token != NULL) {
252                 switch (token_idx) {
253                 case 0:
254                     if (sscanf(token, CF_NAM_FMT,
255                                rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) !=
256                         1)
257                         rrd_set_error("Failed to parse CF name");
258                     switch (cf_conv
259                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
260                     case CF_MHWPREDICT:
261                         strcpy(rrd.stat_head->version, RRD_VERSION);    /* MHWPREDICT causes Version 4 */
262                     case CF_HWPREDICT:
263                         /* initialize some parameters */
264                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
265                             u_val = 0.1;
266                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
267                             u_val = 1.0 / 288;
268                         rrd.rra_def[rrd.stat_head->rra_cnt].
269                             par[RRA_dependent_rra_idx].u_cnt =
270                             rrd.stat_head->rra_cnt;
271                         break;
272                     case CF_DEVSEASONAL:
273                     case CF_SEASONAL:
274                         /* initialize some parameters */
275                         rrd.rra_def[rrd.stat_head->rra_cnt].
276                             par[RRA_seasonal_gamma].u_val = 0.1;
277                         rrd.rra_def[rrd.stat_head->rra_cnt].
278                             par[RRA_seasonal_smoothing_window].u_val = 0.05;
279                         /* fall through */
280                     case CF_DEVPREDICT:
281                         rrd.rra_def[rrd.stat_head->rra_cnt].
282                             par[RRA_dependent_rra_idx].u_cnt = -1;
283                         break;
284                     case CF_FAILURES:
285                         rrd.rra_def[rrd.stat_head->rra_cnt].
286                             par[RRA_delta_pos].u_val = 2.0;
287                         rrd.rra_def[rrd.stat_head->rra_cnt].
288                             par[RRA_delta_neg].u_val = 2.0;
289                         rrd.rra_def[rrd.stat_head->rra_cnt].
290                             par[RRA_window_len].u_cnt = 3;
291                         rrd.rra_def[rrd.stat_head->rra_cnt].
292                             par[RRA_failure_threshold].u_cnt = 2;
293                         rrd.rra_def[rrd.stat_head->rra_cnt].
294                             par[RRA_dependent_rra_idx].u_cnt = -1;
295                         break;
296                         /* invalid consolidation function */
297                     case -1:
298                         rrd_set_error
299                             ("Unrecognized consolidation function %s",
300                              rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
301                     default:
302                         break;
303                     }
304                     /* default: 1 pdp per cdp */
305                     rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1;
306                     break;
307                 case 1:
308                     switch (cf_conv
309                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
310                     case CF_HWPREDICT:
311                     case CF_MHWPREDICT:
312                     case CF_DEVSEASONAL:
313                     case CF_SEASONAL:
314                     case CF_DEVPREDICT:
315                     case CF_FAILURES:
316                         row_cnt = atoi(token);
317                         if (row_cnt <= 0)
318                             rrd_set_error("Invalid row count: %i", row_cnt);
319                         rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
320                         break;
321                     default:
322                         rrd.rra_def[rrd.stat_head->rra_cnt].
323                             par[RRA_cdp_xff_val].u_val = atof(token);
324                         if (rrd.rra_def[rrd.stat_head->rra_cnt].
325                             par[RRA_cdp_xff_val].u_val < 0.0
326                             || rrd.rra_def[rrd.stat_head->rra_cnt].
327                             par[RRA_cdp_xff_val].u_val >= 1.0)
328                             rrd_set_error
329                                 ("Invalid xff: must be between 0 and 1");
330                         break;
331                     }
332                     break;
333                 case 2:
334                     switch (cf_conv
335                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
336                     case CF_HWPREDICT:
337                     case CF_MHWPREDICT:
338                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
339                             u_val = atof(token);
340                         if (atof(token) <= 0.0 || atof(token) >= 1.0)
341                             rrd_set_error
342                                 ("Invalid alpha: must be between 0 and 1");
343                         break;
344                     case CF_DEVSEASONAL:
345                     case CF_SEASONAL:
346                         rrd.rra_def[rrd.stat_head->rra_cnt].
347                             par[RRA_seasonal_gamma].u_val = atof(token);
348                         if (atof(token) <= 0.0 || atof(token) >= 1.0)
349                             rrd_set_error
350                                 ("Invalid gamma: must be between 0 and 1");
351                         rrd.rra_def[rrd.stat_head->rra_cnt].
352                             par[RRA_seasonal_smooth_idx].u_cnt =
353                             hashed_name %
354                             rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt;
355                         break;
356                     case CF_FAILURES:
357                         /* specifies the # of violations that constitutes the failure threshold */
358                         rrd.rra_def[rrd.stat_head->rra_cnt].
359                             par[RRA_failure_threshold].u_cnt = atoi(token);
360                         if (atoi(token) < 1
361                             || atoi(token) > MAX_FAILURES_WINDOW_LEN)
362                             rrd_set_error
363                                 ("Failure threshold is out of range %d, %d",
364                                  1, MAX_FAILURES_WINDOW_LEN);
365                         break;
366                     case CF_DEVPREDICT:
367                         /* specifies the index (1-based) of CF_DEVSEASONAL array
368                          * associated with this CF_DEVPREDICT array. */
369                         rrd.rra_def[rrd.stat_head->rra_cnt].
370                             par[RRA_dependent_rra_idx].u_cnt =
371                             atoi(token) - 1;
372                         break;
373                     default:
374                         rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt =
375                             atoi(token);
376                         if (atoi(token) < 1)
377                             rrd_set_error("Invalid step: must be >= 1");
378                         break;
379                     }
380                     break;
381                 case 3:
382                     switch (cf_conv
383                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
384                     case CF_HWPREDICT:
385                     case CF_MHWPREDICT:
386                         rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
387                             u_val = atof(token);
388                         if (atof(token) < 0.0 || atof(token) > 1.0)
389                             rrd_set_error
390                                 ("Invalid beta: must be between 0 and 1");
391                         break;
392                     case CF_DEVSEASONAL:
393                     case CF_SEASONAL:
394                         /* specifies the index (1-based) of CF_HWPREDICT array
395                          * associated with this CF_DEVSEASONAL or CF_SEASONAL array. 
396                          * */
397                         rrd.rra_def[rrd.stat_head->rra_cnt].
398                             par[RRA_dependent_rra_idx].u_cnt =
399                             atoi(token) - 1;
400                         break;
401                     case CF_FAILURES:
402                         /* specifies the window length */
403                         rrd.rra_def[rrd.stat_head->rra_cnt].
404                             par[RRA_window_len].u_cnt = atoi(token);
405                         if (atoi(token) < 1
406                             || atoi(token) > MAX_FAILURES_WINDOW_LEN)
407                             rrd_set_error
408                                 ("Window length is out of range %d, %d", 1,
409                                  MAX_FAILURES_WINDOW_LEN);
410                         /* verify that window length exceeds the failure threshold */
411                         if (rrd.rra_def[rrd.stat_head->rra_cnt].
412                             par[RRA_window_len].u_cnt <
413                             rrd.rra_def[rrd.stat_head->rra_cnt].
414                             par[RRA_failure_threshold].u_cnt)
415                             rrd_set_error
416                                 ("Window length is shorter than the failure threshold");
417                         break;
418                     case CF_DEVPREDICT:
419                         /* shouldn't be any more arguments */
420                         rrd_set_error
421                             ("Unexpected extra argument for consolidation function DEVPREDICT");
422                         break;
423                     default:
424                         row_cnt = atoi(token);
425                         if (row_cnt <= 0)
426                             rrd_set_error("Invalid row count: %i", row_cnt);
427                         rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
428                         break;
429                     }
430                     break;
431                 case 4:
432                     switch (cf_conv
433                             (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
434                     case CF_FAILURES:
435                         /* specifies the index (1-based) of CF_DEVSEASONAL array
436                          * associated with this CF_DEVFAILURES array. */
437                         rrd.rra_def[rrd.stat_head->rra_cnt].
438                             par[RRA_dependent_rra_idx].u_cnt =
439                             atoi(token) - 1;
440                         break;
441                     case CF_DEVSEASONAL:
442                     case CF_SEASONAL:
443                         /* optional smoothing window */
444                         if (sscanf(token, "smoothing-window=%lf",
445                                    &(rrd.rra_def[rrd.stat_head->rra_cnt].
446                                      par[RRA_seasonal_smoothing_window].
447                                      u_val))) {
448                             strcpy(rrd.stat_head->version, RRD_VERSION);    /* smoothing-window causes Version 4 */
449                             if (rrd.rra_def[rrd.stat_head->rra_cnt].
450                                 par[RRA_seasonal_smoothing_window].u_val < 0.0
451                                 || rrd.rra_def[rrd.stat_head->rra_cnt].
452                                 par[RRA_seasonal_smoothing_window].u_val >
453                                 1.0) {
454                                 rrd_set_error
455                                     ("Invalid smoothing-window %f: must be between 0 and 1",
456                                      rrd.rra_def[rrd.stat_head->rra_cnt].
457                                      par[RRA_seasonal_smoothing_window].
458                                      u_val);
459                             }
460                         } else {
461                             rrd_set_error("Invalid option %s", token);
462                         }
463                         break;
464                     case CF_HWPREDICT:
465                     case CF_MHWPREDICT:
466                         /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
467                         period = atoi(token);
468                         if (period >
469                             rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt)
470                             rrd_set_error
471                                 ("Length of seasonal cycle exceeds length of HW prediction array");
472                         break;
473                     default:
474                         /* shouldn't be any more arguments */
475                         rrd_set_error
476                             ("Unexpected extra argument for consolidation function %s",
477                              rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
478                         break;
479                     }
480                     break;
481                 case 5:
482                     /* If we are here, this must be a CF_HWPREDICT RRA.
483                      * Specifies the index (1-based) of CF_SEASONAL array
484                      * associated with this CF_HWPREDICT array. If this argument 
485                      * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT,
486                      * CF_FAILURES.
487                      * arrays are created automatically. */
488                     rrd.rra_def[rrd.stat_head->rra_cnt].
489                         par[RRA_dependent_rra_idx].u_cnt = atoi(token) - 1;
490                     break;
491                 default:
492                     /* should never get here */
493                     rrd_set_error("Unknown error");
494                     break;
495                 }       /* end switch */
496                 if (rrd_test_error()) {
497                     /* all errors are unrecoverable */
498                     free(argvcopy);
499                     rrd_free2(&rrd);
500                     return (-1);
501                 }
502                 token = strtok_r(NULL, ":", &tokptr);
503                 token_idx++;
504             }           /* end while */
505             free(argvcopy);
506 #ifdef DEBUG
507             fprintf(stderr,
508                     "Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
509                     rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
510                     rrd.rra_def[rrd.stat_head->rra_cnt].
511                     par[RRA_dependent_rra_idx].u_cnt, rrd.stat_head->rra_cnt);
512 #endif
513             /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
514             if ((cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
515                  CF_HWPREDICT
516                  || cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
517                  CF_MHWPREDICT)
518                 && rrd.rra_def[rrd.stat_head->rra_cnt].
519                 par[RRA_dependent_rra_idx].u_cnt == rrd.stat_head->rra_cnt) {
520 #ifdef DEBUG
521                 fprintf(stderr, "Creating HW contingent RRAs\n");
522 #endif
523                 if (create_hw_contingent_rras(&rrd, period, hashed_name) ==
524                     -1) {
525                     rrd_set_error("creating contingent RRA");
526                     rrd_free2(&rrd);
527                     return -1;
528                 }
529             }
530             rrd.stat_head->rra_cnt++;
531         } else {
532             rrd_set_error("can't parse argument '%s'", argv[i]);
533             rrd_free2(&rrd);
534             return -1;
535         }
536     }
537
538
539     if (rrd.stat_head->rra_cnt < 1) {
540         rrd_set_error("you must define at least one Round Robin Archive");
541         rrd_free2(&rrd);
542         return (-1);
543     }
544
545     if (rrd.stat_head->ds_cnt < 1) {
546         rrd_set_error("you must define at least one Data Source");
547         rrd_free2(&rrd);
548         return (-1);
549     }
550     return rrd_create_fn(filename, &rrd);
551 }
552
553 void parseGENERIC_DS(
554     const char *def,
555     rrd_t *rrd,
556     int ds_idx)
557 {
558     char      minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];
559     char     *old_locale;
560
561     /*
562        int temp;
563
564        temp = sscanf(def,"%lu:%18[^:]:%18[^:]", 
565        &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
566        minstr,maxstr);
567      */
568     old_locale = setlocale(LC_NUMERIC, "C");
569     if (sscanf(def, "%lu:%18[^:]:%18[^:]",
570                &(rrd->ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
571                minstr, maxstr) == 3) {
572         if (minstr[0] == 'U' && minstr[1] == 0)
573             rrd->ds_def[ds_idx].par[DS_min_val].u_val = DNAN;
574         else
575             rrd->ds_def[ds_idx].par[DS_min_val].u_val = atof(minstr);
576
577         if (maxstr[0] == 'U' && maxstr[1] == 0)
578             rrd->ds_def[ds_idx].par[DS_max_val].u_val = DNAN;
579         else
580             rrd->ds_def[ds_idx].par[DS_max_val].u_val = atof(maxstr);
581
582         if (!isnan(rrd->ds_def[ds_idx].par[DS_min_val].u_val) &&
583             !isnan(rrd->ds_def[ds_idx].par[DS_max_val].u_val) &&
584             rrd->ds_def[ds_idx].par[DS_min_val].u_val
585             >= rrd->ds_def[ds_idx].par[DS_max_val].u_val) {
586             rrd_set_error("min must be less than max in DS definition");
587             setlocale(LC_NUMERIC, old_locale);
588             return;
589         }
590     } else {
591         rrd_set_error("failed to parse data source %s", def);
592     }
593     setlocale(LC_NUMERIC, old_locale);
594 }
595
596 /* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs
597  * associated with a CF_HWPREDICT RRA. */
598 int create_hw_contingent_rras(
599     rrd_t *rrd,
600     unsigned short period,
601     unsigned long hashed_name)
602 {
603     size_t    old_size;
604     rra_def_t *current_rra;
605
606     /* save index to CF_HWPREDICT */
607     unsigned long hw_index = rrd->stat_head->rra_cnt;
608
609     /* advance the pointer */
610     (rrd->stat_head->rra_cnt)++;
611     /* allocate the memory for the 4 contingent RRAs */
612     old_size = sizeof(rra_def_t) * (rrd->stat_head->rra_cnt);
613     if ((rrd->rra_def = (rra_def_t*)rrd_realloc(rrd->rra_def,
614                                     old_size + 4 * sizeof(rra_def_t))) ==
615         NULL) {
616         rrd_free2(rrd);
617         rrd_set_error("allocating rrd.rra_def");
618         return (-1);
619     }
620     /* clear memory */
621     memset(&(rrd->rra_def[rrd->stat_head->rra_cnt]), 0,
622            4 * sizeof(rra_def_t));
623
624     /* create the CF_SEASONAL RRA */
625     current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
626     strcpy(current_rra->cf_nam, "SEASONAL");
627     current_rra->row_cnt = period;
628     current_rra->par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
629     current_rra->pdp_cnt = 1;
630     current_rra->par[RRA_seasonal_gamma].u_val =
631         rrd->rra_def[hw_index].par[RRA_hw_alpha].u_val;
632     current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index;
633     rrd->rra_def[hw_index].par[RRA_dependent_rra_idx].u_cnt =
634         rrd->stat_head->rra_cnt;
635
636     /* create the CF_DEVSEASONAL RRA */
637     (rrd->stat_head->rra_cnt)++;
638     current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
639     strcpy(current_rra->cf_nam, "DEVSEASONAL");
640     current_rra->row_cnt = period;
641     current_rra->par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
642     current_rra->pdp_cnt = 1;
643     current_rra->par[RRA_seasonal_gamma].u_val =
644         rrd->rra_def[hw_index].par[RRA_hw_alpha].u_val;
645     current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index;
646
647     /* create the CF_DEVPREDICT RRA */
648     (rrd->stat_head->rra_cnt)++;
649     current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
650     strcpy(current_rra->cf_nam, "DEVPREDICT");
651     current_rra->row_cnt = (rrd->rra_def[hw_index]).row_cnt;
652     current_rra->pdp_cnt = 1;
653     current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index + 2;   /* DEVSEASONAL */
654
655     /* create the CF_FAILURES RRA */
656     (rrd->stat_head->rra_cnt)++;
657     current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
658     strcpy(current_rra->cf_nam, "FAILURES");
659     current_rra->row_cnt = period;
660     current_rra->pdp_cnt = 1;
661     current_rra->par[RRA_delta_pos].u_val = 2.0;
662     current_rra->par[RRA_delta_neg].u_val = 2.0;
663     current_rra->par[RRA_failure_threshold].u_cnt = 7;
664     current_rra->par[RRA_window_len].u_cnt = 9;
665     current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index + 2;   /* DEVSEASONAL */
666     return 0;
667 }
668
669 /* create and empty rrd file according to the specs given */
670
671 int rrd_create_fn(
672     const char *file_name,
673     rrd_t *rrd)
674 {
675     unsigned long i, ii;
676     rrd_value_t *unknown;
677     int       unkn_cnt;
678     rrd_file_t *rrd_file_dn;
679     rrd_t     rrd_dn;
680     unsigned  rrd_flags = RRD_READWRITE | RRD_CREAT;
681
682     unkn_cnt = 0;
683     for (i = 0; i < rrd->stat_head->rra_cnt; i++)
684         unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt;
685
686     if ((rrd_file_dn = rrd_open(file_name, rrd, rrd_flags)) == NULL) {
687         rrd_set_error("creating '%s': %s", file_name, rrd_strerror(errno));
688         rrd_free2(rrd);
689         return (-1);
690     }
691
692     rrd_write(rrd_file_dn, rrd->stat_head, sizeof(stat_head_t));
693
694     rrd_write(rrd_file_dn, rrd->ds_def, sizeof(ds_def_t) * rrd->stat_head->ds_cnt);
695
696     rrd_write(rrd_file_dn, rrd->rra_def,
697           sizeof(rra_def_t) * rrd->stat_head->rra_cnt);
698
699     rrd_write(rrd_file_dn, rrd->live_head, sizeof(live_head_t));
700
701     if ((rrd->pdp_prep = (pdp_prep_t*)calloc(1, sizeof(pdp_prep_t))) == NULL) {
702         rrd_set_error("allocating pdp_prep");
703         rrd_free2(rrd);
704         rrd_close(rrd_file_dn);
705         return (-1);
706     }
707
708     strcpy(rrd->pdp_prep->last_ds, "U");
709
710     rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
711     rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt =
712         rrd->live_head->last_up % rrd->stat_head->pdp_step;
713
714     for (i = 0; i < rrd->stat_head->ds_cnt; i++)
715         rrd_write(rrd_file_dn, rrd->pdp_prep, sizeof(pdp_prep_t));
716
717     if ((rrd->cdp_prep = (cdp_prep_t*)calloc(1, sizeof(cdp_prep_t))) == NULL) {
718         rrd_set_error("allocating cdp_prep");
719         rrd_free2(rrd);
720         rrd_close(rrd_file_dn);
721         return (-1);
722     }
723
724
725     for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
726         switch (cf_conv(rrd->rra_def[i].cf_nam)) {
727         case CF_HWPREDICT:
728         case CF_MHWPREDICT:
729             init_hwpredict_cdp(rrd->cdp_prep);
730             break;
731         case CF_SEASONAL:
732         case CF_DEVSEASONAL:
733             init_seasonal_cdp(rrd->cdp_prep);
734             break;
735         case CF_FAILURES:
736             /* initialize violation history to 0 */
737             for (ii = 0; ii < MAX_CDP_PAR_EN; ii++) {
738                 /* We can zero everything out, by setting u_val to the
739                  * NULL address. Each array entry in scratch is 8 bytes
740                  * (a double), but u_cnt only accessed 4 bytes (long) */
741                 rrd->cdp_prep->scratch[ii].u_val = 0.0;
742             }
743             break;
744         default:
745             /* can not be zero because we don't know anything ... */
746             rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
747             /* startup missing pdp count */
748             rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt =
749                 ((rrd->live_head->last_up -
750                   rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
751                  % (rrd->stat_head->pdp_step
752                     * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;
753             break;
754         }
755
756         for (ii = 0; ii < rrd->stat_head->ds_cnt; ii++) {
757             rrd_write(rrd_file_dn, rrd->cdp_prep, sizeof(cdp_prep_t));
758         }
759     }
760
761     /* now, we must make sure that the rest of the rrd
762        struct is properly initialized */
763
764     if ((rrd->rra_ptr = (rra_ptr_t*)calloc(1, sizeof(rra_ptr_t))) == NULL) {
765         rrd_set_error("allocating rra_ptr");
766         rrd_free2(rrd);
767         rrd_close(rrd_file_dn);
768         return (-1);
769     }
770
771     /* changed this initialization to be consistent with
772      * rrd_restore. With the old value (0), the first update
773      * would occur for cur_row = 1 because rrd_update increments
774      * the pointer a priori. */
775     for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
776         rrd->rra_ptr->cur_row = rrd_select_initial_row(rrd_file_dn, i, &rrd->rra_def[i]);
777         rrd_write(rrd_file_dn, rrd->rra_ptr, sizeof(rra_ptr_t));
778     }
779
780     /* write the empty data area */
781     if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) {
782         rrd_set_error("allocating unknown");
783         rrd_free2(rrd);
784         rrd_close(rrd_file_dn);
785         return (-1);
786     }
787     for (i = 0; i < 512; ++i)
788         unknown[i] = DNAN;
789
790     while (unkn_cnt > 0) {
791         if(rrd_write(rrd_file_dn, unknown, sizeof(rrd_value_t) * min(unkn_cnt, 512)) < 0)
792         {
793             rrd_set_error("creating rrd: %s", rrd_strerror(errno));
794             return -1;
795         }
796
797         unkn_cnt -= 512;
798     }
799     free(unknown);
800     rrd_free2(rrd);
801     if (rrd_close(rrd_file_dn) == -1) {
802         rrd_set_error("creating rrd: %s", rrd_strerror(errno));
803         return -1;
804     }
805     /* flush all we don't need out of the cache */
806     rrd_init(&rrd_dn);
807     if((rrd_file_dn = rrd_open(file_name, &rrd_dn, RRD_READONLY)) != NULL)
808     {
809         rrd_dontneed(rrd_file_dn, &rrd_dn);
810         /* rrd_free(&rrd_dn); */
811         rrd_close(rrd_file_dn);
812     }
813     return (0);
814 }
815
816
817 static void rrd_free2(
818     rrd_t *rrd)
819 {
820     free(rrd->live_head);
821     free(rrd->stat_head);
822     free(rrd->ds_def);
823     free(rrd->rra_def);
824     free(rrd->rra_ptr);
825     free(rrd->pdp_prep);
826     free(rrd->cdp_prep);
827     free(rrd->rrd_value);
828 }
829