d36cf3cfa8751a2435cd0958fd6be5b6abdb0fcd
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("what is the name of the rrd file you want 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 /* initialize some parameters */
251 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
252 u_val = 0.1;
253 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
254 u_val = 1.0 / 288;
255 rrd.rra_def[rrd.stat_head->rra_cnt].
256 par[RRA_dependent_rra_idx].u_cnt =
257 rrd.stat_head->rra_cnt;
258 break;
259 case CF_DEVSEASONAL:
260 case CF_SEASONAL:
261 /* initialize some parameters */
262 rrd.rra_def[rrd.stat_head->rra_cnt].
263 par[RRA_seasonal_gamma].u_val = 0.1;
264 /* fall through */
265 case CF_DEVPREDICT:
266 rrd.rra_def[rrd.stat_head->rra_cnt].
267 par[RRA_dependent_rra_idx].u_cnt = -1;
268 break;
269 case CF_FAILURES:
270 rrd.rra_def[rrd.stat_head->rra_cnt].
271 par[RRA_delta_pos].u_val = 2.0;
272 rrd.rra_def[rrd.stat_head->rra_cnt].
273 par[RRA_delta_neg].u_val = 2.0;
274 rrd.rra_def[rrd.stat_head->rra_cnt].
275 par[RRA_window_len].u_cnt = 3;
276 rrd.rra_def[rrd.stat_head->rra_cnt].
277 par[RRA_failure_threshold].u_cnt = 2;
278 rrd.rra_def[rrd.stat_head->rra_cnt].
279 par[RRA_dependent_rra_idx].u_cnt = -1;
280 break;
281 /* invalid consolidation function */
282 case -1:
283 rrd_set_error
284 ("Unrecognized consolidation function %s",
285 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
286 default:
287 break;
288 }
289 /* default: 1 pdp per cdp */
290 rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1;
291 break;
292 case 1:
293 switch (cf_conv
294 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
295 case CF_HWPREDICT:
296 case CF_DEVSEASONAL:
297 case CF_SEASONAL:
298 case CF_DEVPREDICT:
299 case CF_FAILURES:
300 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt =
301 atoi(token);
302 break;
303 default:
304 rrd.rra_def[rrd.stat_head->rra_cnt].
305 par[RRA_cdp_xff_val].u_val = atof(token);
306 if (rrd.rra_def[rrd.stat_head->rra_cnt].
307 par[RRA_cdp_xff_val].u_val < 0.0
308 || rrd.rra_def[rrd.stat_head->rra_cnt].
309 par[RRA_cdp_xff_val].u_val >= 1.0)
310 rrd_set_error
311 ("Invalid xff: must be between 0 and 1");
312 break;
313 }
314 break;
315 case 2:
316 switch (cf_conv
317 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
318 case CF_HWPREDICT:
319 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
320 u_val = atof(token);
321 if (atof(token) <= 0.0 || atof(token) >= 1.0)
322 rrd_set_error
323 ("Invalid alpha: must be between 0 and 1");
324 break;
325 case CF_DEVSEASONAL:
326 case CF_SEASONAL:
327 rrd.rra_def[rrd.stat_head->rra_cnt].
328 par[RRA_seasonal_gamma].u_val = atof(token);
329 if (atof(token) <= 0.0 || atof(token) >= 1.0)
330 rrd_set_error
331 ("Invalid gamma: must be between 0 and 1");
332 rrd.rra_def[rrd.stat_head->rra_cnt].
333 par[RRA_seasonal_smooth_idx].u_cnt =
334 hashed_name %
335 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt;
336 break;
337 case CF_FAILURES:
338 /* specifies the # of violations that constitutes the failure threshold */
339 rrd.rra_def[rrd.stat_head->rra_cnt].
340 par[RRA_failure_threshold].u_cnt = atoi(token);
341 if (atoi(token) < 1
342 || atoi(token) > MAX_FAILURES_WINDOW_LEN)
343 rrd_set_error
344 ("Failure threshold is out of range %d, %d",
345 1, MAX_FAILURES_WINDOW_LEN);
346 break;
347 case CF_DEVPREDICT:
348 /* specifies the index (1-based) of CF_DEVSEASONAL array
349 * associated with this CF_DEVPREDICT array. */
350 rrd.rra_def[rrd.stat_head->rra_cnt].
351 par[RRA_dependent_rra_idx].u_cnt =
352 atoi(token) - 1;
353 break;
354 default:
355 rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt =
356 atoi(token);
357 break;
358 }
359 break;
360 case 3:
361 switch (cf_conv
362 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
363 case CF_HWPREDICT:
364 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
365 u_val = atof(token);
366 if (atof(token) < 0.0 || atof(token) > 1.0)
367 rrd_set_error
368 ("Invalid beta: must be between 0 and 1");
369 break;
370 case CF_DEVSEASONAL:
371 case CF_SEASONAL:
372 /* specifies the index (1-based) of CF_HWPREDICT array
373 * associated with this CF_DEVSEASONAL or CF_SEASONAL array.
374 * */
375 rrd.rra_def[rrd.stat_head->rra_cnt].
376 par[RRA_dependent_rra_idx].u_cnt =
377 atoi(token) - 1;
378 break;
379 case CF_FAILURES:
380 /* specifies the window length */
381 rrd.rra_def[rrd.stat_head->rra_cnt].
382 par[RRA_window_len].u_cnt = atoi(token);
383 if (atoi(token) < 1
384 || atoi(token) > MAX_FAILURES_WINDOW_LEN)
385 rrd_set_error
386 ("Window length is out of range %d, %d", 1,
387 MAX_FAILURES_WINDOW_LEN);
388 /* verify that window length exceeds the failure threshold */
389 if (rrd.rra_def[rrd.stat_head->rra_cnt].
390 par[RRA_window_len].u_cnt <
391 rrd.rra_def[rrd.stat_head->rra_cnt].
392 par[RRA_failure_threshold].u_cnt)
393 rrd_set_error
394 ("Window length is shorter than the failure threshold");
395 break;
396 case CF_DEVPREDICT:
397 /* shouldn't be any more arguments */
398 rrd_set_error
399 ("Unexpected extra argument for consolidation function DEVPREDICT");
400 break;
401 default:
402 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt =
403 atoi(token);
404 break;
405 }
406 break;
407 case 4:
408 switch (cf_conv
409 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
410 case CF_FAILURES:
411 /* specifies the index (1-based) of CF_DEVSEASONAL array
412 * associated with this CF_DEVFAILURES array. */
413 rrd.rra_def[rrd.stat_head->rra_cnt].
414 par[RRA_dependent_rra_idx].u_cnt =
415 atoi(token) - 1;
416 break;
417 case CF_HWPREDICT:
418 /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
419 period = atoi(token);
420 if (period >
421 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt)
422 rrd_set_error
423 ("Length of seasonal cycle exceeds length of HW prediction array");
424 break;
425 default:
426 /* shouldn't be any more arguments */
427 rrd_set_error
428 ("Unexpected extra argument for consolidation function %s",
429 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
430 break;
431 }
432 break;
433 case 5:
434 /* If we are here, this must be a CF_HWPREDICT RRA.
435 * Specifies the index (1-based) of CF_SEASONAL array
436 * associated with this CF_HWPREDICT array. If this argument
437 * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT,
438 * CF_FAILURES.
439 * arrays are created automatically. */
440 rrd.rra_def[rrd.stat_head->rra_cnt].
441 par[RRA_dependent_rra_idx].u_cnt = atoi(token) - 1;
442 break;
443 default:
444 /* should never get here */
445 rrd_set_error("Unknown error");
446 break;
447 } /* end switch */
448 if (rrd_test_error()) {
449 /* all errors are unrecoverable */
450 free(argvcopy);
451 rrd_free(&rrd);
452 return (-1);
453 }
454 token = strtok_r(NULL, ":", &tokptr);
455 token_idx++;
456 } /* end while */
457 free(argvcopy);
458 #ifdef DEBUG
459 fprintf(stderr,
460 "Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
461 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
462 rrd.rra_def[rrd.stat_head->rra_cnt].
463 par[RRA_dependent_rra_idx].u_cnt, rrd.stat_head->rra_cnt);
464 #endif
465 /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
466 if (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
467 CF_HWPREDICT
468 && rrd.rra_def[rrd.stat_head->rra_cnt].
469 par[RRA_dependent_rra_idx].u_cnt == rrd.stat_head->rra_cnt) {
470 #ifdef DEBUG
471 fprintf(stderr, "Creating HW contingent RRAs\n");
472 #endif
473 if (create_hw_contingent_rras(&rrd, period, hashed_name) ==
474 -1) {
475 rrd_set_error("creating contingent RRA");
476 rrd_free(&rrd);
477 return -1;
478 }
479 }
480 rrd.stat_head->rra_cnt++;
481 } else {
482 rrd_set_error("can't parse argument '%s'", argv[i]);
483 rrd_free(&rrd);
484 return -1;
485 }
486 }
489 if (rrd.stat_head->rra_cnt < 1) {
490 rrd_set_error("you must define at least one Round Robin Archive");
491 rrd_free(&rrd);
492 return (-1);
493 }
495 if (rrd.stat_head->ds_cnt < 1) {
496 rrd_set_error("you must define at least one Data Source");
497 rrd_free(&rrd);
498 return (-1);
499 }
500 return rrd_create_fn(filename, &rrd);
501 }
503 void parseGENERIC_DS(
504 const char *def,
505 rrd_t *rrd,
506 int ds_idx)
507 {
508 char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];
510 /*
511 int temp;
513 temp = sscanf(def,"%lu:%18[^:]:%18[^:]",
514 &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
515 minstr,maxstr);
516 */
517 if (sscanf(def, "%lu:%18[^:]:%18[^:]",
518 &(rrd->ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
519 minstr, maxstr) == 3) {
520 if (minstr[0] == 'U' && minstr[1] == 0)
521 rrd->ds_def[ds_idx].par[DS_min_val].u_val = DNAN;
522 else
523 rrd->ds_def[ds_idx].par[DS_min_val].u_val = atof(minstr);
525 if (maxstr[0] == 'U' && maxstr[1] == 0)
526 rrd->ds_def[ds_idx].par[DS_max_val].u_val = DNAN;
527 else
528 rrd->ds_def[ds_idx].par[DS_max_val].u_val = atof(maxstr);
530 if (!isnan(rrd->ds_def[ds_idx].par[DS_min_val].u_val) &&
531 !isnan(rrd->ds_def[ds_idx].par[DS_max_val].u_val) &&
532 rrd->ds_def[ds_idx].par[DS_min_val].u_val
533 >= rrd->ds_def[ds_idx].par[DS_max_val].u_val) {
534 rrd_set_error("min must be less than max in DS definition");
535 return;
536 }
537 } else {
538 rrd_set_error("failed to parse data source %s", def);
539 }
540 }
542 /* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs
543 * associated with a CF_HWPREDICT RRA. */
544 int create_hw_contingent_rras(
545 rrd_t *rrd,
546 unsigned short period,
547 unsigned long hashed_name)
548 {
549 size_t old_size;
550 rra_def_t *current_rra;
552 /* save index to CF_HWPREDICT */
553 unsigned long hw_index = rrd->stat_head->rra_cnt;
555 /* advance the pointer */
556 (rrd->stat_head->rra_cnt)++;
557 /* allocate the memory for the 4 contingent RRAs */
558 old_size = sizeof(rra_def_t) * (rrd->stat_head->rra_cnt);
559 if ((rrd->rra_def = rrd_realloc(rrd->rra_def,
560 old_size + 4 * sizeof(rra_def_t))) ==
561 NULL) {
562 rrd_set_error("allocating rrd.rra_def");
563 return (-1);
564 }
565 /* clear memory */
566 memset(&(rrd->rra_def[rrd->stat_head->rra_cnt]), 0,
567 4 * sizeof(rra_def_t));
569 /* create the CF_SEASONAL RRA */
570 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
571 strcpy(current_rra->cf_nam, "SEASONAL");
572 current_rra->row_cnt = period;
573 current_rra->par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
574 current_rra->pdp_cnt = 1;
575 current_rra->par[RRA_seasonal_gamma].u_val =
576 rrd->rra_def[hw_index].par[RRA_hw_alpha].u_val;
577 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index;
578 rrd->rra_def[hw_index].par[RRA_dependent_rra_idx].u_cnt =
579 rrd->stat_head->rra_cnt;
581 /* create the CF_DEVSEASONAL RRA */
582 (rrd->stat_head->rra_cnt)++;
583 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
584 strcpy(current_rra->cf_nam, "DEVSEASONAL");
585 current_rra->row_cnt = period;
586 current_rra->par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
587 current_rra->pdp_cnt = 1;
588 current_rra->par[RRA_seasonal_gamma].u_val =
589 rrd->rra_def[hw_index].par[RRA_hw_alpha].u_val;
590 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index;
592 /* create the CF_DEVPREDICT RRA */
593 (rrd->stat_head->rra_cnt)++;
594 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
595 strcpy(current_rra->cf_nam, "DEVPREDICT");
596 current_rra->row_cnt = (rrd->rra_def[hw_index]).row_cnt;
597 current_rra->pdp_cnt = 1;
598 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index + 2; /* DEVSEASONAL */
600 /* create the CF_FAILURES RRA */
601 (rrd->stat_head->rra_cnt)++;
602 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
603 strcpy(current_rra->cf_nam, "FAILURES");
604 current_rra->row_cnt = period;
605 current_rra->pdp_cnt = 1;
606 current_rra->par[RRA_delta_pos].u_val = 2.0;
607 current_rra->par[RRA_delta_neg].u_val = 2.0;
608 current_rra->par[RRA_failure_threshold].u_cnt = 7;
609 current_rra->par[RRA_window_len].u_cnt = 9;
610 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index + 2; /* DEVSEASONAL */
611 return 0;
612 }
614 /* create and empty rrd file according to the specs given */
616 int rrd_create_fn(
617 const char *file_name,
618 rrd_t *rrd)
619 {
620 unsigned long i, ii;
621 FILE *rrd_file;
622 rrd_value_t *unknown;
623 int unkn_cnt;
625 long rrd_head_size;
627 if ((rrd_file = fopen(file_name, "wb")) == NULL) {
628 rrd_set_error("creating '%s': %s", file_name, rrd_strerror(errno));
629 free(rrd->stat_head);
630 rrd->stat_head = NULL;
631 free(rrd->ds_def);
632 rrd->ds_def = NULL;
633 free(rrd->rra_def);
634 rrd->rra_def = NULL;
635 return (-1);
636 }
638 fwrite(rrd->stat_head, sizeof(stat_head_t), 1, rrd_file);
640 fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
642 fwrite(rrd->rra_def,
643 sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
645 fwrite(rrd->live_head, sizeof(live_head_t), 1, rrd_file);
647 if ((rrd->pdp_prep = calloc(1, sizeof(pdp_prep_t))) == NULL) {
648 rrd_set_error("allocating pdp_prep");
649 rrd_free(rrd);
650 fclose(rrd_file);
651 return (-1);
652 }
654 strcpy(rrd->pdp_prep->last_ds, "UNKN");
656 rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
657 rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt =
658 rrd->live_head->last_up % rrd->stat_head->pdp_step;
660 for (i = 0; i < rrd->stat_head->ds_cnt; i++)
661 fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), 1, rrd_file);
663 if ((rrd->cdp_prep = calloc(1, sizeof(cdp_prep_t))) == NULL) {
664 rrd_set_error("allocating cdp_prep");
665 rrd_free(rrd);
666 fclose(rrd_file);
667 return (-1);
668 }
671 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
672 switch (cf_conv(rrd->rra_def[i].cf_nam)) {
673 case CF_HWPREDICT:
674 init_hwpredict_cdp(rrd->cdp_prep);
675 break;
676 case CF_SEASONAL:
677 case CF_DEVSEASONAL:
678 init_seasonal_cdp(rrd->cdp_prep);
679 break;
680 case CF_FAILURES:
681 /* initialize violation history to 0 */
682 for (ii = 0; ii < MAX_CDP_PAR_EN; ii++) {
683 /* We can zero everything out, by setting u_val to the
684 * NULL address. Each array entry in scratch is 8 bytes
685 * (a double), but u_cnt only accessed 4 bytes (long) */
686 rrd->cdp_prep->scratch[ii].u_val = 0.0;
687 }
688 break;
689 default:
690 /* can not be zero because we don't know anything ... */
691 rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
692 /* startup missing pdp count */
693 rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt =
694 ((rrd->live_head->last_up -
695 rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
696 % (rrd->stat_head->pdp_step
697 * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;
698 break;
699 }
701 for (ii = 0; ii < rrd->stat_head->ds_cnt; ii++) {
702 fwrite(rrd->cdp_prep, sizeof(cdp_prep_t), 1, rrd_file);
703 }
704 }
706 /* now, we must make sure that the rest of the rrd
707 struct is properly initialized */
709 if ((rrd->rra_ptr = calloc(1, sizeof(rra_ptr_t))) == NULL) {
710 rrd_set_error("allocating rra_ptr");
711 rrd_free(rrd);
712 fclose(rrd_file);
713 return (-1);
714 }
716 /* changed this initialization to be consistent with
717 * rrd_restore. With the old value (0), the first update
718 * would occur for cur_row = 1 because rrd_update increments
719 * the pointer a priori. */
720 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
721 rrd->rra_ptr->cur_row = rrd->rra_def[i].row_cnt - 1;
722 fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), 1, rrd_file);
723 }
724 rrd_head_size = ftell(rrd_file);
726 /* write the empty data area */
727 if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) {
728 rrd_set_error("allocating unknown");
729 rrd_free(rrd);
730 fclose(rrd_file);
731 return (-1);
732 }
733 for (i = 0; i < 512; ++i)
734 unknown[i] = DNAN;
736 unkn_cnt = 0;
737 for (i = 0; i < rrd->stat_head->rra_cnt; i++)
738 unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt;
740 while (unkn_cnt > 0) {
741 fwrite(unknown, sizeof(rrd_value_t), min(unkn_cnt, 512), rrd_file);
742 unkn_cnt -= 512;
743 }
744 free(unknown);
746 /* lets see if we had an error */
747 if (ferror(rrd_file)) {
748 rrd_set_error("a file error occurred while creating '%s'", file_name);
749 fclose(rrd_file);
750 rrd_free(rrd);
751 return (-1);
752 }
753 #ifdef HAVE_POSIX_FADVISE
754 /* this file is not going to be read again any time
755 soon, so we drop everything except the header portion from
756 the buffer cache. for this to work, we have to fdsync the file
757 first though. This will not be all that fast, but 'good' data
758 like other rrdfiles headers will stay in cache. Now this only works if creating
759 a single rrd file is not too large, but I assume this should not be the case
760 in general. Otherwhise we would have to sync and release while writing all
761 the unknown data. */
762 fflush(rrd_file);
763 fdatasync(fileno(rrd_file));
764 if (0 !=
765 posix_fadvise(fileno(rrd_file), rrd_head_size, 0,
766 POSIX_FADV_DONTNEED)) {
767 rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s", file_name,
768 rrd_strerror(errno));
769 fclose(rrd_file);
770 return (-1);
771 }
772 #endif
774 fclose(rrd_file);
775 rrd_free(rrd);
776 return (0);
777 }