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