1 /*****************************************************************************
2 * RRDtool 1.4.4 Copyright by Tobi Oetiker, 1997-2010
3 *****************************************************************************
4 * rrd_create.c creates new rrds
5 *****************************************************************************/
7 #include <stdlib.h>
8 #include <time.h>
9 #include <locale.h>
11 #include "rrd_tool.h"
12 #include "rrd_rpncalc.h"
13 #include "rrd_hw.h"
15 #include "rrd_is_thread_safe.h"
16 static int opt_no_overwrite = 0;
18 #ifdef WIN32
19 # include <process.h>
20 #endif
22 unsigned long FnvHash(
23 const char *str);
24 int create_hw_contingent_rras(
25 rrd_t *rrd,
26 unsigned short period,
27 unsigned long hashed_name);
28 void parseGENERIC_DS(
29 const char *def,
30 rrd_t *rrd,
31 int ds_idx);
33 static void rrd_free2(
34 rrd_t *rrd); /* our onwn copy, immmune to mmap */
36 int rrd_create(
37 int argc,
38 char **argv)
39 {
40 struct option long_options[] = {
41 {"start", required_argument, 0, 'b'},
42 {"step", required_argument, 0, 's'},
43 {"no-overwrite", no_argument, 0, 'O'},
44 {0, 0, 0, 0}
45 };
46 int option_index = 0;
47 int opt;
48 time_t last_up = time(NULL) - 10;
49 unsigned long pdp_step = 300;
50 rrd_time_value_t last_up_tv;
51 char *parsetime_error = NULL;
52 long long_tmp;
53 int rc;
55 optind = 0;
56 opterr = 0; /* initialize getopt */
58 while (1) {
59 opt = getopt_long(argc, argv, "Ob:s:", long_options, &option_index);
61 if (opt == EOF)
62 break;
64 switch (opt) {
65 case 'b':
66 if ((parsetime_error = rrd_parsetime(optarg, &last_up_tv))) {
67 rrd_set_error("start time: %s", parsetime_error);
68 return (-1);
69 }
70 if (last_up_tv.type == RELATIVE_TO_END_TIME ||
71 last_up_tv.type == RELATIVE_TO_START_TIME) {
72 rrd_set_error("specifying time relative to the 'start' "
73 "or 'end' makes no sense here");
74 return (-1);
75 }
77 last_up = mktime(&last_up_tv.tm) +last_up_tv.offset;
79 if (last_up < 3600 * 24 * 365 * 10) {
80 rrd_set_error
81 ("the first entry to the RRD should be after 1980");
82 return (-1);
83 }
84 break;
86 case 's':
87 long_tmp = atol(optarg);
88 if (long_tmp < 1) {
89 rrd_set_error("step size should be no less than one second");
90 return (-1);
91 }
92 pdp_step = long_tmp;
93 break;
95 case 'O':
96 opt_no_overwrite = 1;
97 break;
99 case '?':
100 if (optopt != 0)
101 rrd_set_error("unknown option '%c'", optopt);
102 else
103 rrd_set_error("unknown option '%s'", argv[optind - 1]);
104 return (-1);
105 }
106 }
107 if (optind == argc) {
108 rrd_set_error("need name of an rrd file to create");
109 return -1;
110 }
111 rc = rrd_create_r(argv[optind],
112 pdp_step, last_up,
113 argc - optind - 1, (const char **) (argv + optind + 1));
115 return rc;
116 }
118 /* #define DEBUG */
119 int rrd_create_r(
120 const char *filename,
121 unsigned long pdp_step,
122 time_t last_up,
123 int argc,
124 const char **argv)
125 {
126 rrd_t rrd;
127 long i;
128 int offset;
129 char *token;
130 char dummychar1[2], dummychar2[2];
131 unsigned short token_idx, error_flag, period = 0;
132 unsigned long hashed_name;
134 /* init rrd clean */
135 rrd_init(&rrd);
136 /* static header */
137 if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
138 rrd_set_error("allocating rrd.stat_head");
139 rrd_free2(&rrd);
140 return (-1);
141 }
143 /* live header */
144 if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) {
145 rrd_set_error("allocating rrd.live_head");
146 rrd_free2(&rrd);
147 return (-1);
148 }
150 /* set some defaults */
151 strcpy(rrd.stat_head->cookie, RRD_COOKIE);
152 strcpy(rrd.stat_head->version, RRD_VERSION3); /* by default we are still version 3 */
153 rrd.stat_head->float_cookie = FLOAT_COOKIE;
154 rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
155 rrd.stat_head->rra_cnt = 0; /* ditto */
156 rrd.stat_head->pdp_step = pdp_step; /* 5 minute default */
158 /* a default value */
159 rrd.ds_def = NULL;
160 rrd.rra_def = NULL;
162 rrd.live_head->last_up = last_up;
164 /* optind points to the first non-option command line arg,
165 * in this case, the file name. */
166 /* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL
167 * arrays. */
168 hashed_name = FnvHash(filename);
169 for (i = 0; i < argc; i++) {
170 unsigned int ii;
172 if (strncmp(argv[i], "DS:", 3) == 0) {
173 size_t old_size = sizeof(ds_def_t) * (rrd.stat_head->ds_cnt);
175 if ((rrd.ds_def = (ds_def_t*)rrd_realloc(rrd.ds_def,
176 old_size + sizeof(ds_def_t))) ==
177 NULL) {
178 rrd_set_error("allocating rrd.ds_def");
179 rrd_free2(&rrd);
180 return (-1);
181 }
182 memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
183 /* extract the name and type */
184 switch (sscanf(&argv[i][3],
185 DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
186 rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
187 dummychar1,
188 rrd.ds_def[rrd.stat_head->ds_cnt].dst,
189 dummychar2, &offset)) {
190 case 0:
191 case 1:
192 rrd_set_error("Invalid DS name");
193 break;
194 case 2:
195 case 3:
196 rrd_set_error("Invalid DS type");
197 break;
198 case 4: /* (%n may or may not be counted) */
199 case 5: /* check for duplicate datasource names */
200 for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++)
201 if (strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
202 rrd.ds_def[ii].ds_nam) == 0)
203 rrd_set_error("Duplicate DS name: %s",
204 rrd.ds_def[ii].ds_nam);
205 /* DS_type may be valid or not. Checked later */
206 break;
207 default:
208 rrd_set_error("invalid DS format");
209 }
210 if (rrd_test_error()) {
211 rrd_free2(&rrd);
212 return -1;
213 }
215 /* parse the remainder of the arguments */
216 switch (dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst)) {
217 case DST_COUNTER:
218 case DST_ABSOLUTE:
219 case DST_GAUGE:
220 case DST_DERIVE:
221 parseGENERIC_DS(&argv[i][offset + 3], &rrd,
222 rrd.stat_head->ds_cnt);
223 break;
224 case DST_CDEF:
225 parseCDEF_DS(&argv[i][offset + 3], &rrd,
226 rrd.stat_head->ds_cnt);
227 break;
228 default:
229 rrd_set_error("invalid DS type specified");
230 break;
231 }
233 if (rrd_test_error()) {
234 rrd_free2(&rrd);
235 return -1;
236 }
237 rrd.stat_head->ds_cnt++;
238 } else if (strncmp(argv[i], "RRA:", 4) == 0) {
239 char *argvcopy;
240 char *tokptr = "";
241 size_t old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt);
242 int row_cnt;
244 if ((rrd.rra_def = (rra_def_t*)rrd_realloc(rrd.rra_def,
245 old_size + sizeof(rra_def_t))) ==
246 NULL) {
247 rrd_set_error("allocating rrd.rra_def");
248 rrd_free2(&rrd);
249 return (-1);
250 }
251 memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0,
252 sizeof(rra_def_t));
254 argvcopy = strdup(argv[i]);
255 token = strtok_r(&argvcopy[4], ":", &tokptr);
256 token_idx = error_flag = 0;
257 while (token != NULL) {
258 switch (token_idx) {
259 case 0:
260 if (sscanf(token, CF_NAM_FMT,
261 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) !=
262 1)
263 rrd_set_error("Failed to parse CF name");
264 switch (cf_conv
265 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
266 case CF_MHWPREDICT:
267 strcpy(rrd.stat_head->version, RRD_VERSION); /* MHWPREDICT causes Version 4 */
268 case CF_HWPREDICT:
269 /* initialize some parameters */
270 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
271 u_val = 0.1;
272 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
273 u_val = 1.0 / 288;
274 rrd.rra_def[rrd.stat_head->rra_cnt].
275 par[RRA_dependent_rra_idx].u_cnt =
276 rrd.stat_head->rra_cnt;
277 break;
278 case CF_DEVSEASONAL:
279 case CF_SEASONAL:
280 /* initialize some parameters */
281 rrd.rra_def[rrd.stat_head->rra_cnt].
282 par[RRA_seasonal_gamma].u_val = 0.1;
283 rrd.rra_def[rrd.stat_head->rra_cnt].
284 par[RRA_seasonal_smoothing_window].u_val = 0.05;
285 /* fall through */
286 case CF_DEVPREDICT:
287 rrd.rra_def[rrd.stat_head->rra_cnt].
288 par[RRA_dependent_rra_idx].u_cnt = -1;
289 break;
290 case CF_FAILURES:
291 rrd.rra_def[rrd.stat_head->rra_cnt].
292 par[RRA_delta_pos].u_val = 2.0;
293 rrd.rra_def[rrd.stat_head->rra_cnt].
294 par[RRA_delta_neg].u_val = 2.0;
295 rrd.rra_def[rrd.stat_head->rra_cnt].
296 par[RRA_window_len].u_cnt = 3;
297 rrd.rra_def[rrd.stat_head->rra_cnt].
298 par[RRA_failure_threshold].u_cnt = 2;
299 rrd.rra_def[rrd.stat_head->rra_cnt].
300 par[RRA_dependent_rra_idx].u_cnt = -1;
301 break;
302 /* invalid consolidation function */
303 case -1:
304 rrd_set_error
305 ("Unrecognized consolidation function %s",
306 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
307 default:
308 break;
309 }
310 /* default: 1 pdp per cdp */
311 rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1;
312 break;
313 case 1:
314 switch (cf_conv
315 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
316 case CF_HWPREDICT:
317 case CF_MHWPREDICT:
318 case CF_DEVSEASONAL:
319 case CF_SEASONAL:
320 case CF_DEVPREDICT:
321 case CF_FAILURES:
322 row_cnt = atoi(token);
323 if (row_cnt <= 0)
324 rrd_set_error("Invalid row count: %i", row_cnt);
325 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
326 break;
327 default:
328 rrd.rra_def[rrd.stat_head->rra_cnt].
329 par[RRA_cdp_xff_val].u_val = atof(token);
330 if (rrd.rra_def[rrd.stat_head->rra_cnt].
331 par[RRA_cdp_xff_val].u_val < 0.0
332 || rrd.rra_def[rrd.stat_head->rra_cnt].
333 par[RRA_cdp_xff_val].u_val >= 1.0)
334 rrd_set_error
335 ("Invalid xff: must be between 0 and 1");
336 break;
337 }
338 break;
339 case 2:
340 switch (cf_conv
341 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
342 case CF_HWPREDICT:
343 case CF_MHWPREDICT:
344 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].
345 u_val = atof(token);
346 if (atof(token) <= 0.0 || atof(token) >= 1.0)
347 rrd_set_error
348 ("Invalid alpha: must be between 0 and 1");
349 break;
350 case CF_DEVSEASONAL:
351 case CF_SEASONAL:
352 rrd.rra_def[rrd.stat_head->rra_cnt].
353 par[RRA_seasonal_gamma].u_val = atof(token);
354 if (atof(token) <= 0.0 || atof(token) >= 1.0)
355 rrd_set_error
356 ("Invalid gamma: must be between 0 and 1");
357 rrd.rra_def[rrd.stat_head->rra_cnt].
358 par[RRA_seasonal_smooth_idx].u_cnt =
359 hashed_name %
360 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt;
361 break;
362 case CF_FAILURES:
363 /* specifies the # of violations that constitutes the failure threshold */
364 rrd.rra_def[rrd.stat_head->rra_cnt].
365 par[RRA_failure_threshold].u_cnt = atoi(token);
366 if (atoi(token) < 1
367 || atoi(token) > MAX_FAILURES_WINDOW_LEN)
368 rrd_set_error
369 ("Failure threshold is out of range %d, %d",
370 1, MAX_FAILURES_WINDOW_LEN);
371 break;
372 case CF_DEVPREDICT:
373 /* specifies the index (1-based) of CF_DEVSEASONAL array
374 * associated with this CF_DEVPREDICT array. */
375 rrd.rra_def[rrd.stat_head->rra_cnt].
376 par[RRA_dependent_rra_idx].u_cnt =
377 atoi(token) - 1;
378 break;
379 default:
380 rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt =
381 atoi(token);
382 if (atoi(token) < 1)
383 rrd_set_error("Invalid step: must be >= 1");
384 break;
385 }
386 break;
387 case 3:
388 switch (cf_conv
389 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
390 case CF_HWPREDICT:
391 case CF_MHWPREDICT:
392 rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].
393 u_val = atof(token);
394 if (atof(token) < 0.0 || atof(token) > 1.0)
395 rrd_set_error
396 ("Invalid beta: must be between 0 and 1");
397 break;
398 case CF_DEVSEASONAL:
399 case CF_SEASONAL:
400 /* specifies the index (1-based) of CF_HWPREDICT array
401 * associated with this CF_DEVSEASONAL or CF_SEASONAL array.
402 * */
403 rrd.rra_def[rrd.stat_head->rra_cnt].
404 par[RRA_dependent_rra_idx].u_cnt =
405 atoi(token) - 1;
406 break;
407 case CF_FAILURES:
408 /* specifies the window length */
409 rrd.rra_def[rrd.stat_head->rra_cnt].
410 par[RRA_window_len].u_cnt = atoi(token);
411 if (atoi(token) < 1
412 || atoi(token) > MAX_FAILURES_WINDOW_LEN)
413 rrd_set_error
414 ("Window length is out of range %d, %d", 1,
415 MAX_FAILURES_WINDOW_LEN);
416 /* verify that window length exceeds the failure threshold */
417 if (rrd.rra_def[rrd.stat_head->rra_cnt].
418 par[RRA_window_len].u_cnt <
419 rrd.rra_def[rrd.stat_head->rra_cnt].
420 par[RRA_failure_threshold].u_cnt)
421 rrd_set_error
422 ("Window length is shorter than the failure threshold");
423 break;
424 case CF_DEVPREDICT:
425 /* shouldn't be any more arguments */
426 rrd_set_error
427 ("Unexpected extra argument for consolidation function DEVPREDICT");
428 break;
429 default:
430 row_cnt = atoi(token);
431 if (row_cnt <= 0)
432 rrd_set_error("Invalid row count: %i", row_cnt);
433 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt;
434 break;
435 }
436 break;
437 case 4:
438 switch (cf_conv
439 (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
440 case CF_FAILURES:
441 /* specifies the index (1-based) of CF_DEVSEASONAL array
442 * associated with this CF_DEVFAILURES array. */
443 rrd.rra_def[rrd.stat_head->rra_cnt].
444 par[RRA_dependent_rra_idx].u_cnt =
445 atoi(token) - 1;
446 break;
447 case CF_DEVSEASONAL:
448 case CF_SEASONAL:
449 /* optional smoothing window */
450 if (sscanf(token, "smoothing-window=%lf",
451 &(rrd.rra_def[rrd.stat_head->rra_cnt].
452 par[RRA_seasonal_smoothing_window].
453 u_val))) {
454 strcpy(rrd.stat_head->version, RRD_VERSION); /* smoothing-window causes Version 4 */
455 if (rrd.rra_def[rrd.stat_head->rra_cnt].
456 par[RRA_seasonal_smoothing_window].u_val < 0.0
457 || rrd.rra_def[rrd.stat_head->rra_cnt].
458 par[RRA_seasonal_smoothing_window].u_val >
459 1.0) {
460 rrd_set_error
461 ("Invalid smoothing-window %f: must be between 0 and 1",
462 rrd.rra_def[rrd.stat_head->rra_cnt].
463 par[RRA_seasonal_smoothing_window].
464 u_val);
465 }
466 } else {
467 rrd_set_error("Invalid option %s", token);
468 }
469 break;
470 case CF_HWPREDICT:
471 case CF_MHWPREDICT:
472 /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */
473 period = atoi(token);
474 if (period >
475 rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt)
476 rrd_set_error
477 ("Length of seasonal cycle exceeds length of HW prediction array");
478 break;
479 default:
480 /* shouldn't be any more arguments */
481 rrd_set_error
482 ("Unexpected extra argument for consolidation function %s",
483 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
484 break;
485 }
486 break;
487 case 5:
488 /* If we are here, this must be a CF_HWPREDICT RRA.
489 * Specifies the index (1-based) of CF_SEASONAL array
490 * associated with this CF_HWPREDICT array. If this argument
491 * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT,
492 * CF_FAILURES.
493 * arrays are created automatically. */
494 rrd.rra_def[rrd.stat_head->rra_cnt].
495 par[RRA_dependent_rra_idx].u_cnt = atoi(token) - 1;
496 break;
497 default:
498 /* should never get here */
499 rrd_set_error("Unknown error");
500 break;
501 } /* end switch */
502 if (rrd_test_error()) {
503 /* all errors are unrecoverable */
504 free(argvcopy);
505 rrd_free2(&rrd);
506 return (-1);
507 }
508 token = strtok_r(NULL, ":", &tokptr);
509 token_idx++;
510 } /* end while */
511 free(argvcopy);
512 #ifdef DEBUG
513 fprintf(stderr,
514 "Creating RRA CF: %s, dep idx %lu, current idx %lu\n",
515 rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
516 rrd.rra_def[rrd.stat_head->rra_cnt].
517 par[RRA_dependent_rra_idx].u_cnt, rrd.stat_head->rra_cnt);
518 #endif
519 /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */
520 if ((cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
521 CF_HWPREDICT
522 || cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
523 CF_MHWPREDICT)
524 && rrd.rra_def[rrd.stat_head->rra_cnt].
525 par[RRA_dependent_rra_idx].u_cnt == rrd.stat_head->rra_cnt) {
526 #ifdef DEBUG
527 fprintf(stderr, "Creating HW contingent RRAs\n");
528 #endif
529 if (create_hw_contingent_rras(&rrd, period, hashed_name) ==
530 -1) {
531 rrd_set_error("creating contingent RRA");
532 rrd_free2(&rrd);
533 return -1;
534 }
535 }
536 rrd.stat_head->rra_cnt++;
537 } else {
538 rrd_set_error("can't parse argument '%s'", argv[i]);
539 rrd_free2(&rrd);
540 return -1;
541 }
542 }
545 if (rrd.stat_head->rra_cnt < 1) {
546 rrd_set_error("you must define at least one Round Robin Archive");
547 rrd_free2(&rrd);
548 return (-1);
549 }
551 if (rrd.stat_head->ds_cnt < 1) {
552 rrd_set_error("you must define at least one Data Source");
553 rrd_free2(&rrd);
554 return (-1);
555 }
556 return rrd_create_fn(filename, &rrd);
557 }
559 void parseGENERIC_DS(
560 const char *def,
561 rrd_t *rrd,
562 int ds_idx)
563 {
564 char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];
565 char *old_locale;
567 /*
568 int temp;
570 temp = sscanf(def,"%lu:%18[^:]:%18[^:]",
571 &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
572 minstr,maxstr);
573 */
574 old_locale = setlocale(LC_NUMERIC, NULL);
575 setlocale(LC_NUMERIC, "C");
576 if (sscanf(def, "%lu:%18[^:]:%18[^:]",
577 &(rrd->ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt),
578 minstr, maxstr) == 3) {
579 if (minstr[0] == 'U' && minstr[1] == 0)
580 rrd->ds_def[ds_idx].par[DS_min_val].u_val = DNAN;
581 else
582 rrd->ds_def[ds_idx].par[DS_min_val].u_val = atof(minstr);
584 if (maxstr[0] == 'U' && maxstr[1] == 0)
585 rrd->ds_def[ds_idx].par[DS_max_val].u_val = DNAN;
586 else
587 rrd->ds_def[ds_idx].par[DS_max_val].u_val = atof(maxstr);
589 if (!isnan(rrd->ds_def[ds_idx].par[DS_min_val].u_val) &&
590 !isnan(rrd->ds_def[ds_idx].par[DS_max_val].u_val) &&
591 rrd->ds_def[ds_idx].par[DS_min_val].u_val
592 >= rrd->ds_def[ds_idx].par[DS_max_val].u_val) {
593 rrd_set_error("min must be less than max in DS definition");
594 setlocale(LC_NUMERIC, old_locale);
595 return;
596 }
597 } else {
598 rrd_set_error("failed to parse data source %s", def);
599 }
600 setlocale(LC_NUMERIC, old_locale);
601 }
603 /* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs
604 * associated with a CF_HWPREDICT RRA. */
605 int create_hw_contingent_rras(
606 rrd_t *rrd,
607 unsigned short period,
608 unsigned long hashed_name)
609 {
610 size_t old_size;
611 rra_def_t *current_rra;
613 /* save index to CF_HWPREDICT */
614 unsigned long hw_index = rrd->stat_head->rra_cnt;
616 /* advance the pointer */
617 (rrd->stat_head->rra_cnt)++;
618 /* allocate the memory for the 4 contingent RRAs */
619 old_size = sizeof(rra_def_t) * (rrd->stat_head->rra_cnt);
620 if ((rrd->rra_def = (rra_def_t*)rrd_realloc(rrd->rra_def,
621 old_size + 4 * sizeof(rra_def_t))) ==
622 NULL) {
623 rrd_free2(rrd);
624 rrd_set_error("allocating rrd.rra_def");
625 return (-1);
626 }
627 /* clear memory */
628 memset(&(rrd->rra_def[rrd->stat_head->rra_cnt]), 0,
629 4 * sizeof(rra_def_t));
631 /* create the CF_SEASONAL RRA */
632 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
633 strcpy(current_rra->cf_nam, "SEASONAL");
634 current_rra->row_cnt = period;
635 current_rra->par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
636 current_rra->pdp_cnt = 1;
637 current_rra->par[RRA_seasonal_gamma].u_val =
638 rrd->rra_def[hw_index].par[RRA_hw_alpha].u_val;
639 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index;
640 rrd->rra_def[hw_index].par[RRA_dependent_rra_idx].u_cnt =
641 rrd->stat_head->rra_cnt;
643 /* create the CF_DEVSEASONAL RRA */
644 (rrd->stat_head->rra_cnt)++;
645 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
646 strcpy(current_rra->cf_nam, "DEVSEASONAL");
647 current_rra->row_cnt = period;
648 current_rra->par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period;
649 current_rra->pdp_cnt = 1;
650 current_rra->par[RRA_seasonal_gamma].u_val =
651 rrd->rra_def[hw_index].par[RRA_hw_alpha].u_val;
652 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index;
654 /* create the CF_DEVPREDICT RRA */
655 (rrd->stat_head->rra_cnt)++;
656 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
657 strcpy(current_rra->cf_nam, "DEVPREDICT");
658 current_rra->row_cnt = (rrd->rra_def[hw_index]).row_cnt;
659 current_rra->pdp_cnt = 1;
660 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index + 2; /* DEVSEASONAL */
662 /* create the CF_FAILURES RRA */
663 (rrd->stat_head->rra_cnt)++;
664 current_rra = &(rrd->rra_def[rrd->stat_head->rra_cnt]);
665 strcpy(current_rra->cf_nam, "FAILURES");
666 current_rra->row_cnt = period;
667 current_rra->pdp_cnt = 1;
668 current_rra->par[RRA_delta_pos].u_val = 2.0;
669 current_rra->par[RRA_delta_neg].u_val = 2.0;
670 current_rra->par[RRA_failure_threshold].u_cnt = 7;
671 current_rra->par[RRA_window_len].u_cnt = 9;
672 current_rra->par[RRA_dependent_rra_idx].u_cnt = hw_index + 2; /* DEVSEASONAL */
673 return 0;
674 }
676 /* create and empty rrd file according to the specs given */
678 int rrd_create_fn(
679 const char *file_name,
680 rrd_t *rrd)
681 {
682 unsigned long i, ii;
683 rrd_value_t *unknown;
684 int unkn_cnt;
685 rrd_file_t *rrd_file_dn;
686 rrd_t rrd_dn;
687 unsigned rrd_flags = RRD_READWRITE | RRD_CREAT;
689 if (opt_no_overwrite) {
690 rrd_flags |= RRD_EXCL ;
691 }
693 unkn_cnt = 0;
694 for (i = 0; i < rrd->stat_head->rra_cnt; i++)
695 unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt;
697 if ((rrd_file_dn = rrd_open(file_name, rrd, rrd_flags)) == NULL) {
698 rrd_set_error("creating '%s': %s", file_name, rrd_strerror(errno));
699 rrd_free2(rrd);
700 return (-1);
701 }
703 rrd_write(rrd_file_dn, rrd->stat_head, sizeof(stat_head_t));
705 rrd_write(rrd_file_dn, rrd->ds_def, sizeof(ds_def_t) * rrd->stat_head->ds_cnt);
707 rrd_write(rrd_file_dn, rrd->rra_def,
708 sizeof(rra_def_t) * rrd->stat_head->rra_cnt);
710 rrd_write(rrd_file_dn, rrd->live_head, sizeof(live_head_t));
712 if ((rrd->pdp_prep = (pdp_prep_t*)calloc(1, sizeof(pdp_prep_t))) == NULL) {
713 rrd_set_error("allocating pdp_prep");
714 rrd_free2(rrd);
715 rrd_close(rrd_file_dn);
716 return (-1);
717 }
719 strcpy(rrd->pdp_prep->last_ds, "U");
721 rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
722 rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt =
723 rrd->live_head->last_up % rrd->stat_head->pdp_step;
725 for (i = 0; i < rrd->stat_head->ds_cnt; i++)
726 rrd_write(rrd_file_dn, rrd->pdp_prep, sizeof(pdp_prep_t));
728 if ((rrd->cdp_prep = (cdp_prep_t*)calloc(1, sizeof(cdp_prep_t))) == NULL) {
729 rrd_set_error("allocating cdp_prep");
730 rrd_free2(rrd);
731 rrd_close(rrd_file_dn);
732 return (-1);
733 }
736 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
737 switch (cf_conv(rrd->rra_def[i].cf_nam)) {
738 case CF_HWPREDICT:
739 case CF_MHWPREDICT:
740 init_hwpredict_cdp(rrd->cdp_prep);
741 break;
742 case CF_SEASONAL:
743 case CF_DEVSEASONAL:
744 init_seasonal_cdp(rrd->cdp_prep);
745 break;
746 case CF_FAILURES:
747 /* initialize violation history to 0 */
748 for (ii = 0; ii < MAX_CDP_PAR_EN; ii++) {
749 /* We can zero everything out, by setting u_val to the
750 * NULL address. Each array entry in scratch is 8 bytes
751 * (a double), but u_cnt only accessed 4 bytes (long) */
752 rrd->cdp_prep->scratch[ii].u_val = 0.0;
753 }
754 break;
755 default:
756 /* can not be zero because we don't know anything ... */
757 rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
758 /* startup missing pdp count */
759 rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt =
760 ((rrd->live_head->last_up -
761 rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
762 % (rrd->stat_head->pdp_step
763 * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;
764 break;
765 }
767 for (ii = 0; ii < rrd->stat_head->ds_cnt; ii++) {
768 rrd_write(rrd_file_dn, rrd->cdp_prep, sizeof(cdp_prep_t));
769 }
770 }
772 /* now, we must make sure that the rest of the rrd
773 struct is properly initialized */
775 if ((rrd->rra_ptr = (rra_ptr_t*)calloc(1, sizeof(rra_ptr_t))) == NULL) {
776 rrd_set_error("allocating rra_ptr");
777 rrd_free2(rrd);
778 rrd_close(rrd_file_dn);
779 return (-1);
780 }
782 /* changed this initialization to be consistent with
783 * rrd_restore. With the old value (0), the first update
784 * would occur for cur_row = 1 because rrd_update increments
785 * the pointer a priori. */
786 for (i = 0; i < rrd->stat_head->rra_cnt; i++) {
787 rrd->rra_ptr->cur_row = rrd_select_initial_row(rrd_file_dn, i, &rrd->rra_def[i]);
788 rrd_write(rrd_file_dn, rrd->rra_ptr, sizeof(rra_ptr_t));
789 }
791 /* write the empty data area */
792 if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) {
793 rrd_set_error("allocating unknown");
794 rrd_free2(rrd);
795 rrd_close(rrd_file_dn);
796 return (-1);
797 }
798 for (i = 0; i < 512; ++i)
799 unknown[i] = DNAN;
801 while (unkn_cnt > 0) {
802 if(rrd_write(rrd_file_dn, unknown, sizeof(rrd_value_t) * min(unkn_cnt, 512)) < 0)
803 {
804 rrd_set_error("creating rrd: %s", rrd_strerror(errno));
805 return -1;
806 }
808 unkn_cnt -= 512;
809 }
810 free(unknown);
811 rrd_free2(rrd);
812 if (rrd_close(rrd_file_dn) == -1) {
813 rrd_set_error("creating rrd: %s", rrd_strerror(errno));
814 return -1;
815 }
816 /* flush all we don't need out of the cache */
817 rrd_init(&rrd_dn);
818 if((rrd_file_dn = rrd_open(file_name, &rrd_dn, RRD_READONLY)) != NULL)
819 {
820 rrd_dontneed(rrd_file_dn, &rrd_dn);
821 /* rrd_free(&rrd_dn); */
822 rrd_close(rrd_file_dn);
823 }
824 return (0);
825 }
828 static void rrd_free2(
829 rrd_t *rrd)
830 {
831 free(rrd->live_head);
832 free(rrd->stat_head);
833 free(rrd->ds_def);
834 free(rrd->rra_def);
835 free(rrd->rra_ptr);
836 free(rrd->pdp_prep);
837 free(rrd->cdp_prep);
838 free(rrd->rrd_value);
839 }