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