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