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