X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_create.c;h=a1b4e5a4efc4bec8ee77dc1ad3b037c41076056a;hp=766b783460e205b7f7132b820b77a6298926209c;hb=8f9c2c2b3c3f8a65e24dd9d8d612eafe48ccfb2e;hpb=51fcea2cbf9721f012f2f0d43c604a3aaf684ee8 diff --git a/src/rrd_create.c b/src/rrd_create.c index 766b783..a1b4e5a 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -1,14 +1,23 @@ /***************************************************************************** - * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007 + * RRDtool 1.4.2 Copyright by Tobi Oetiker, 1997-2009 ***************************************************************************** * rrd_create.c creates new rrds *****************************************************************************/ +#include +#include +#include + #include "rrd_tool.h" #include "rrd_rpncalc.h" #include "rrd_hw.h" #include "rrd_is_thread_safe.h" +static int opt_no_overwrite = 0; + +#ifdef WIN32 +# include +#endif unsigned long FnvHash( const char *str); @@ -21,13 +30,24 @@ void parseGENERIC_DS( rrd_t *rrd, int ds_idx); +static void rrd_free2( + rrd_t *rrd); /* our onwn copy, immmune to mmap */ + int rrd_create( int argc, char **argv) { + struct option long_options[] = { + {"start", required_argument, 0, 'b'}, + {"step", required_argument, 0, 's'}, + {"no-overwrite", no_argument, 0, 'O'}, + {0, 0, 0, 0} + }; + int option_index = 0; + int opt; time_t last_up = time(NULL) - 10; unsigned long pdp_step = 300; - struct rrd_time_value last_up_tv; + rrd_time_value_t last_up_tv; char *parsetime_error = NULL; long long_tmp; int rc; @@ -36,22 +56,14 @@ int rrd_create( opterr = 0; /* initialize getopt */ while (1) { - static struct option long_options[] = { - {"start", required_argument, 0, 'b'}, - {"step", required_argument, 0, 's'}, - {0, 0, 0, 0} - }; - int option_index = 0; - int opt; - - opt = getopt_long(argc, argv, "b:s:", long_options, &option_index); + opt = getopt_long(argc, argv, "Ob:s:", long_options, &option_index); if (opt == EOF) break; switch (opt) { case 'b': - if ((parsetime_error = parsetime(optarg, &last_up_tv))) { + if ((parsetime_error = rrd_parsetime(optarg, &last_up_tv))) { rrd_set_error("start time: %s", parsetime_error); return (-1); } @@ -80,6 +92,10 @@ int rrd_create( pdp_step = long_tmp; break; + case 'O': + opt_no_overwrite = 1; + break; + case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); @@ -118,22 +134,22 @@ int rrd_create_r( /* init rrd clean */ rrd_init(&rrd); /* static header */ - if ((rrd.stat_head = calloc(1, sizeof(stat_head_t))) == NULL) { + if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) { rrd_set_error("allocating rrd.stat_head"); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } /* live header */ - if ((rrd.live_head = calloc(1, sizeof(live_head_t))) == NULL) { + if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) { rrd_set_error("allocating rrd.live_head"); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } /* set some defaults */ strcpy(rrd.stat_head->cookie, RRD_COOKIE); - strcpy(rrd.stat_head->version, RRD_VERSION); + strcpy(rrd.stat_head->version, RRD_VERSION3); /* by default we are still version 3 */ rrd.stat_head->float_cookie = FLOAT_COOKIE; rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */ rrd.stat_head->rra_cnt = 0; /* ditto */ @@ -156,11 +172,11 @@ int rrd_create_r( if (strncmp(argv[i], "DS:", 3) == 0) { size_t old_size = sizeof(ds_def_t) * (rrd.stat_head->ds_cnt); - if ((rrd.ds_def = rrd_realloc(rrd.ds_def, + if ((rrd.ds_def = (ds_def_t*)rrd_realloc(rrd.ds_def, old_size + sizeof(ds_def_t))) == NULL) { rrd_set_error("allocating rrd.ds_def"); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t)); @@ -192,7 +208,7 @@ int rrd_create_r( rrd_set_error("invalid DS format"); } if (rrd_test_error()) { - rrd_free(&rrd); + rrd_free2(&rrd); return -1; } @@ -215,20 +231,21 @@ int rrd_create_r( } if (rrd_test_error()) { - rrd_free(&rrd); + rrd_free2(&rrd); return -1; } rrd.stat_head->ds_cnt++; } else if (strncmp(argv[i], "RRA:", 4) == 0) { char *argvcopy; - char *tokptr; + char *tokptr = ""; size_t old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt); + int row_cnt; - if ((rrd.rra_def = rrd_realloc(rrd.rra_def, + if ((rrd.rra_def = (rra_def_t*)rrd_realloc(rrd.rra_def, old_size + sizeof(rra_def_t))) == NULL) { rrd_set_error("allocating rrd.rra_def"); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, @@ -246,8 +263,9 @@ int rrd_create_r( rrd_set_error("Failed to parse CF name"); switch (cf_conv (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) { - case CF_HWPREDICT: case CF_MHWPREDICT: + strcpy(rrd.stat_head->version, RRD_VERSION); /* MHWPREDICT causes Version 4 */ + case CF_HWPREDICT: /* initialize some parameters */ rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha]. u_val = 0.1; @@ -262,6 +280,8 @@ int rrd_create_r( /* initialize some parameters */ rrd.rra_def[rrd.stat_head->rra_cnt]. par[RRA_seasonal_gamma].u_val = 0.1; + rrd.rra_def[rrd.stat_head->rra_cnt]. + par[RRA_seasonal_smoothing_window].u_val = 0.05; /* fall through */ case CF_DEVPREDICT: rrd.rra_def[rrd.stat_head->rra_cnt]. @@ -299,8 +319,10 @@ int rrd_create_r( case CF_SEASONAL: case CF_DEVPREDICT: case CF_FAILURES: - rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = - atoi(token); + row_cnt = atoi(token); + if (row_cnt <= 0) + rrd_set_error("Invalid row count: %i", row_cnt); + rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt; break; default: rrd.rra_def[rrd.stat_head->rra_cnt]. @@ -357,6 +379,8 @@ int rrd_create_r( default: rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = atoi(token); + if (atoi(token) < 1) + rrd_set_error("Invalid step: must be >= 1"); break; } break; @@ -403,8 +427,10 @@ int rrd_create_r( ("Unexpected extra argument for consolidation function DEVPREDICT"); break; default: - rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = - atoi(token); + row_cnt = atoi(token); + if (row_cnt <= 0) + rrd_set_error("Invalid row count: %i", row_cnt); + rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = row_cnt; break; } break; @@ -418,6 +444,29 @@ int rrd_create_r( par[RRA_dependent_rra_idx].u_cnt = atoi(token) - 1; break; + case CF_DEVSEASONAL: + case CF_SEASONAL: + /* optional smoothing window */ + if (sscanf(token, "smoothing-window=%lf", + &(rrd.rra_def[rrd.stat_head->rra_cnt]. + par[RRA_seasonal_smoothing_window]. + u_val))) { + strcpy(rrd.stat_head->version, RRD_VERSION); /* smoothing-window causes Version 4 */ + if (rrd.rra_def[rrd.stat_head->rra_cnt]. + par[RRA_seasonal_smoothing_window].u_val < 0.0 + || rrd.rra_def[rrd.stat_head->rra_cnt]. + par[RRA_seasonal_smoothing_window].u_val > + 1.0) { + rrd_set_error + ("Invalid smoothing-window %f: must be between 0 and 1", + rrd.rra_def[rrd.stat_head->rra_cnt]. + par[RRA_seasonal_smoothing_window]. + u_val); + } + } else { + rrd_set_error("Invalid option %s", token); + } + break; case CF_HWPREDICT: case CF_MHWPREDICT: /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */ @@ -453,7 +502,7 @@ int rrd_create_r( if (rrd_test_error()) { /* all errors are unrecoverable */ free(argvcopy); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } token = strtok_r(NULL, ":", &tokptr); @@ -480,14 +529,14 @@ int rrd_create_r( if (create_hw_contingent_rras(&rrd, period, hashed_name) == -1) { rrd_set_error("creating contingent RRA"); - rrd_free(&rrd); + rrd_free2(&rrd); return -1; } } rrd.stat_head->rra_cnt++; } else { rrd_set_error("can't parse argument '%s'", argv[i]); - rrd_free(&rrd); + rrd_free2(&rrd); return -1; } } @@ -495,13 +544,13 @@ int rrd_create_r( if (rrd.stat_head->rra_cnt < 1) { rrd_set_error("you must define at least one Round Robin Archive"); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } if (rrd.stat_head->ds_cnt < 1) { rrd_set_error("you must define at least one Data Source"); - rrd_free(&rrd); + rrd_free2(&rrd); return (-1); } return rrd_create_fn(filename, &rrd); @@ -513,6 +562,7 @@ void parseGENERIC_DS( int ds_idx) { char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE]; + char *old_locale; /* int temp; @@ -521,6 +571,7 @@ void parseGENERIC_DS( &(rrd -> ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt), minstr,maxstr); */ + old_locale = setlocale(LC_NUMERIC, "C"); if (sscanf(def, "%lu:%18[^:]:%18[^:]", &(rrd->ds_def[ds_idx].par[DS_mrhb_cnt].u_cnt), minstr, maxstr) == 3) { @@ -539,11 +590,13 @@ void parseGENERIC_DS( rrd->ds_def[ds_idx].par[DS_min_val].u_val >= rrd->ds_def[ds_idx].par[DS_max_val].u_val) { rrd_set_error("min must be less than max in DS definition"); + setlocale(LC_NUMERIC, old_locale); return; } } else { rrd_set_error("failed to parse data source %s", def); } + setlocale(LC_NUMERIC, old_locale); } /* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs @@ -563,9 +616,10 @@ int create_hw_contingent_rras( (rrd->stat_head->rra_cnt)++; /* allocate the memory for the 4 contingent RRAs */ old_size = sizeof(rra_def_t) * (rrd->stat_head->rra_cnt); - if ((rrd->rra_def = rrd_realloc(rrd->rra_def, + if ((rrd->rra_def = (rra_def_t*)rrd_realloc(rrd->rra_def, old_size + 4 * sizeof(rra_def_t))) == NULL) { + rrd_free2(rrd); rrd_set_error("allocating rrd.rra_def"); return (-1); } @@ -625,52 +679,55 @@ int rrd_create_fn( rrd_t *rrd) { unsigned long i, ii; - FILE *rrd_file; rrd_value_t *unknown; int unkn_cnt; + rrd_file_t *rrd_file_dn; + rrd_t rrd_dn; + unsigned rrd_flags = RRD_READWRITE | RRD_CREAT; - long rrd_head_size; + if (opt_no_overwrite) { + rrd_flags |= RRD_EXCL ; + } + + unkn_cnt = 0; + for (i = 0; i < rrd->stat_head->rra_cnt; i++) + unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt; - if ((rrd_file = fopen(file_name, "wb")) == NULL) { + if ((rrd_file_dn = rrd_open(file_name, rrd, rrd_flags)) == NULL) { rrd_set_error("creating '%s': %s", file_name, rrd_strerror(errno)); - free(rrd->stat_head); - rrd->stat_head = NULL; - free(rrd->ds_def); - rrd->ds_def = NULL; - free(rrd->rra_def); - rrd->rra_def = NULL; + rrd_free2(rrd); return (-1); } - fwrite(rrd->stat_head, sizeof(stat_head_t), 1, rrd_file); + rrd_write(rrd_file_dn, rrd->stat_head, sizeof(stat_head_t)); - fwrite(rrd->ds_def, sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file); + rrd_write(rrd_file_dn, rrd->ds_def, sizeof(ds_def_t) * rrd->stat_head->ds_cnt); - fwrite(rrd->rra_def, - sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file); + rrd_write(rrd_file_dn, rrd->rra_def, + sizeof(rra_def_t) * rrd->stat_head->rra_cnt); - fwrite(rrd->live_head, sizeof(live_head_t), 1, rrd_file); + rrd_write(rrd_file_dn, rrd->live_head, sizeof(live_head_t)); - if ((rrd->pdp_prep = calloc(1, sizeof(pdp_prep_t))) == NULL) { + if ((rrd->pdp_prep = (pdp_prep_t*)calloc(1, sizeof(pdp_prep_t))) == NULL) { rrd_set_error("allocating pdp_prep"); - rrd_free(rrd); - fclose(rrd_file); + rrd_free2(rrd); + rrd_close(rrd_file_dn); return (-1); } - strcpy(rrd->pdp_prep->last_ds, "UNKN"); + strcpy(rrd->pdp_prep->last_ds, "U"); rrd->pdp_prep->scratch[PDP_val].u_val = 0.0; rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt = rrd->live_head->last_up % rrd->stat_head->pdp_step; for (i = 0; i < rrd->stat_head->ds_cnt; i++) - fwrite(rrd->pdp_prep, sizeof(pdp_prep_t), 1, rrd_file); + rrd_write(rrd_file_dn, rrd->pdp_prep, sizeof(pdp_prep_t)); - if ((rrd->cdp_prep = calloc(1, sizeof(cdp_prep_t))) == NULL) { + if ((rrd->cdp_prep = (cdp_prep_t*)calloc(1, sizeof(cdp_prep_t))) == NULL) { rrd_set_error("allocating cdp_prep"); - rrd_free(rrd); - fclose(rrd_file); + rrd_free2(rrd); + rrd_close(rrd_file_dn); return (-1); } @@ -707,17 +764,17 @@ int rrd_create_fn( } for (ii = 0; ii < rrd->stat_head->ds_cnt; ii++) { - fwrite(rrd->cdp_prep, sizeof(cdp_prep_t), 1, rrd_file); + rrd_write(rrd_file_dn, rrd->cdp_prep, sizeof(cdp_prep_t)); } } /* now, we must make sure that the rest of the rrd struct is properly initialized */ - if ((rrd->rra_ptr = calloc(1, sizeof(rra_ptr_t))) == NULL) { + if ((rrd->rra_ptr = (rra_ptr_t*)calloc(1, sizeof(rra_ptr_t))) == NULL) { rrd_set_error("allocating rra_ptr"); - rrd_free(rrd); - fclose(rrd_file); + rrd_free2(rrd); + rrd_close(rrd_file_dn); return (-1); } @@ -726,60 +783,57 @@ int rrd_create_fn( * would occur for cur_row = 1 because rrd_update increments * the pointer a priori. */ for (i = 0; i < rrd->stat_head->rra_cnt; i++) { - rrd->rra_ptr->cur_row = rrd->rra_def[i].row_cnt - 1; - fwrite(rrd->rra_ptr, sizeof(rra_ptr_t), 1, rrd_file); + rrd->rra_ptr->cur_row = rrd_select_initial_row(rrd_file_dn, i, &rrd->rra_def[i]); + rrd_write(rrd_file_dn, rrd->rra_ptr, sizeof(rra_ptr_t)); } - rrd_head_size = ftell(rrd_file); /* write the empty data area */ if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) { rrd_set_error("allocating unknown"); - rrd_free(rrd); - fclose(rrd_file); + rrd_free2(rrd); + rrd_close(rrd_file_dn); return (-1); } for (i = 0; i < 512; ++i) unknown[i] = DNAN; - unkn_cnt = 0; - for (i = 0; i < rrd->stat_head->rra_cnt; i++) - unkn_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt; - while (unkn_cnt > 0) { - fwrite(unknown, sizeof(rrd_value_t), min(unkn_cnt, 512), rrd_file); + if(rrd_write(rrd_file_dn, unknown, sizeof(rrd_value_t) * min(unkn_cnt, 512)) < 0) + { + rrd_set_error("creating rrd: %s", rrd_strerror(errno)); + return -1; + } + unkn_cnt -= 512; } free(unknown); - - /* lets see if we had an error */ - if (ferror(rrd_file)) { - rrd_set_error("a file error occurred while creating '%s'", file_name); - fclose(rrd_file); - rrd_free(rrd); - return (-1); + rrd_free2(rrd); + if (rrd_close(rrd_file_dn) == -1) { + rrd_set_error("creating rrd: %s", rrd_strerror(errno)); + return -1; } -#ifdef HAVE_POSIX_FADVISE - /* this file is not going to be read again any time - soon, so we drop everything except the header portion from - the buffer cache. for this to work, we have to fdsync the file - first though. This will not be all that fast, but 'good' data - like other rrdfiles headers will stay in cache. Now this only works if creating - a single rrd file is not too large, but I assume this should not be the case - in general. Otherwhise we would have to sync and release while writing all - the unknown data. */ - fflush(rrd_file); - fdatasync(fileno(rrd_file)); - if (0 != - posix_fadvise(fileno(rrd_file), rrd_head_size, 0, - POSIX_FADV_DONTNEED)) { - rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s", file_name, - rrd_strerror(errno)); - fclose(rrd_file); - return (-1); + /* flush all we don't need out of the cache */ + rrd_init(&rrd_dn); + if((rrd_file_dn = rrd_open(file_name, &rrd_dn, RRD_READONLY)) != NULL) + { + rrd_dontneed(rrd_file_dn, &rrd_dn); + /* rrd_free(&rrd_dn); */ + rrd_close(rrd_file_dn); } -#endif - - fclose(rrd_file); - rrd_free(rrd); return (0); } + + +static void rrd_free2( + rrd_t *rrd) +{ + free(rrd->live_head); + free(rrd->stat_head); + free(rrd->ds_def); + free(rrd->rra_def); + free(rrd->rra_ptr); + free(rrd->pdp_prep); + free(rrd->cdp_prep); + free(rrd->rrd_value); +} +