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