e9ac860dca92c184f1012e5617076933b3dcdb99
1 /*****************************************************************************
2 * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007
3 *****************************************************************************
4 * rrd_create.c creates new rrds
5 *****************************************************************************/
7 #include "rrd_tool.h"
8 #include "rrd_rpncalc.h"
9 #include "rrd_hw.h"
11 #include "rrd_is_thread_safe.h"
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);
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 */
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);
40 if (opt == EOF)
41 break;
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 }
56 last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
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;
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;
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));
89 return rc;
90 }
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;
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 }
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 }
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 */
130 /* a default value */
131 rrd.ds_def = NULL;
132 rrd.rra_def = NULL;
134 rrd.live_head->last_up = last_up;
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 }
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 }
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));
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 }
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 }
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 }
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;
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);
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);
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 }
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;
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));
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;
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;
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 */
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 }
547 /* create and empty rrd file according to the specs given */
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;
557 long rrd_head_size;
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 }
570 fwrite(rrd->stat_head,
571 sizeof(stat_head_t), 1, rrd_file);
573 fwrite(rrd->ds_def,
574 sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
576 fwrite(rrd->rra_def,
577 sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
579 fwrite(rrd->live_head,
580 sizeof(live_head_t),1, rrd_file);
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 }
589 strcpy(rrd->pdp_prep->last_ds,"UNKN");
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;
595 for(i=0; i < rrd->stat_head->ds_cnt; i++)
596 fwrite( rrd->pdp_prep,sizeof(pdp_prep_t),1,rrd_file);
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 }
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 }
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 }
644 /* now, we must make sure that the rest of the rrd
645 struct is properly initialized */
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 }
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);
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;
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;
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);
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 }
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
711 fclose(rrd_file);
712 rrd_free(rrd);
713 return (0);
714 }