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