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