X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_create.c;h=d60e2e91a4208ed365beb5aa6e222fe84a867a07;hp=f118da6fb11e9fdf0bfabd9c8cb7f6e2c589a484;hb=7c016dfa001ae254bf4e18126f814ee8f0abd821;hpb=1f763dfd3c4259aeb0c882291543eb64596906a9 diff --git a/src/rrd_create.c b/src/rrd_create.c index f118da6..d60e2e9 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -6,7 +6,10 @@ #include "rrd_tool.h" +/* prototype for FnvHash */ +unsigned long FnvHash(char *str); +/* #define DEBUG */ int rrd_create(int argc, char **argv) { @@ -15,7 +18,9 @@ rrd_create(int argc, char **argv) time_t last_up; struct time_value last_up_tv; char *parsetime_error = NULL; - + char *token; + unsigned short token_idx, error_flag, period=0; + unsigned long hashed_name; /* init last_up */ last_up = time(NULL)-10; /* init rrd clean */ @@ -34,7 +39,8 @@ rrd_create(int argc, char **argv) /* set some defaults */ strcpy(rrd.stat_head->cookie,RRD_COOKIE); - strcpy(rrd.stat_head->version,RRD_VERSION); + /* assume the will be version 1 compatible */ + strcpy(rrd.stat_head->version,"0001"); 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 */ @@ -103,7 +109,12 @@ rrd_create(int argc, char **argv) } } rrd.live_head->last_up = last_up; - + + /* optind points to the first non-option command line arg, + * in this case, the file name. */ + /* Compute the FNV hash value (used by SEASONAL and DEVSEASONAL + * arrays. */ + hashed_name = FnvHash(argv[optind]); for(i=optind+1;irra_cnt); if((rrd.rra_def = rrd_realloc(rrd.rra_def, - old_size+sizeof(rra_def_t)))==NULL){ - rrd_set_error("allocating rrd.rra_def"); - rrd_free(&rrd); - return(-1); + old_size+sizeof(rra_def_t)))==NULL) + { + rrd_set_error("allocating rrd.rra_def"); + rrd_free(&rrd); + return(-1); } memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t)); - if (sscanf(&argv[i][4], - CF_NAM_FMT ":%lf:%lu:%lu", - rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam, - &rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val, - &rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt, - &rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt) == 4){ - if(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) == -1){ - rrd_free(&rrd); - return (-1); + + token = strtok(&argv[i][4],":"); + token_idx = error_flag = 0; + while (token != NULL) + { + switch(token_idx) + { + case 0: + if (sscanf(token,CF_NAM_FMT, + rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) != 1) + rrd_set_error("Failed to parse CF name"); + switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) + { + case CF_HWPREDICT: + /* initialize some parameters */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].u_val = 0.1; + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].u_val = 1.0/288; + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = + rrd.stat_head -> rra_cnt; + /* need to mark the file version */ + strcpy(rrd.stat_head->version,RRD_VERSION); + break; + case CF_DEVSEASONAL: + case CF_SEASONAL: + /* initialize some parameters */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_seasonal_gamma].u_val = 0.1; + /* fall through */ + case CF_DEVPREDICT: + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = -1; + break; + case CF_FAILURES: + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_delta_pos].u_val = 2.0; + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_delta_neg].u_val = 2.0; + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_window_len].u_cnt = 3; + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_failure_threshold].u_cnt = 2; + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = -1; + break; + /* invalid consolidation function */ + case -1: + rrd_set_error("Unrecognized consolidation function %s", + rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam); + default: + break; } - if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val<0.0 || - rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val>=1.0) { - rrd_set_error("the xff must always be >= 0 and < 1"); - rrd_free(&rrd); - return (-1); + /* default: 1 pdp per cdp */ + rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = 1; + break; + case 1: + switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) + { + case CF_HWPREDICT: + case CF_DEVSEASONAL: + case CF_SEASONAL: + case CF_DEVPREDICT: + case CF_FAILURES: + rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = atoi(token); + break; + default: + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val = atof(token); + if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val<0.0 || + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val>=1.0) + rrd_set_error("Invalid xff: must be between 0 and 1"); + break; } - rrd.stat_head->rra_cnt++; - } - else { - rrd_set_error("can't parse argument '%s'",argv[i]); + break; + case 2: + switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) + { + case CF_HWPREDICT: + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_alpha].u_val = atof(token); + if (atof(token) <= 0.0 || atof(token) >= 1.0) + rrd_set_error("Invalid alpha: must be between 0 and 1"); + break; + case CF_DEVSEASONAL: + case CF_SEASONAL: + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_seasonal_gamma].u_val = + atof(token); + if (atof(token) <= 0.0 || atof(token) >= 1.0) + rrd_set_error("Invalid gamma: must be between 0 and 1"); + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_seasonal_smooth_idx].u_cnt + = hashed_name % rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt; + break; + case CF_FAILURES: + /* specifies the # of violations that constitutes the failure threshold */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_failure_threshold].u_cnt = + atoi(token); + if (atoi(token) < 1 || atoi(token) > MAX_FAILURES_WINDOW_LEN) + rrd_set_error("Failure threshold is out of range %d, %d",1, + MAX_FAILURES_WINDOW_LEN); + break; + case CF_DEVPREDICT: + /* specifies the index (1-based) of CF_DEVSEASONAL array + * associated with this CF_DEVPREDICT array. */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = + atoi(token) - 1; + break; + default: + rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt = atoi(token); + break; + } + break; + case 3: + switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) + { + case CF_HWPREDICT: + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_hw_beta].u_val = atof(token); + if (atof(token) < 0.0 || atof(token) > 1.0) + rrd_set_error("Invalid beta: must be between 0 and 1"); + break; + case CF_DEVSEASONAL: + case CF_SEASONAL: + /* specifies the index (1-based) of CF_HWPREDICT array + * associated with this CF_DEVSEASONAL or CF_SEASONAL array. + * */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = + atoi(token) - 1; + break; + case CF_FAILURES: + /* specifies the window length */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_window_len].u_cnt = + atoi(token); + if (atoi(token) < 1 || atoi(token) > MAX_FAILURES_WINDOW_LEN) + rrd_set_error("Window length is out of range %d, %d",1, + MAX_FAILURES_WINDOW_LEN); + /* verify that window length exceeds the failure threshold */ + if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_window_len].u_cnt < + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_failure_threshold].u_cnt) + rrd_set_error("Window length is shorter than the failure threshold"); + break; + case CF_DEVPREDICT: + /* shouldn't be any more arguments */ + rrd_set_error("Unexpected extra argument for consolidation function DEVPREDICT"); + break; + default: + rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt = atoi(token); + break; + } + break; + case 4: + switch(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) + { + case CF_FAILURES: + /* specifies the index (1-based) of CF_DEVSEASONAL array + * associated with this CF_DEVFAILURES array. */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = + atoi(token) - 1; + break; + case CF_HWPREDICT: + /* length of the associated CF_SEASONAL and CF_DEVSEASONAL arrays. */ + period = atoi(token); + if (period > rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt) + rrd_set_error("Length of seasonal cycle exceeds length of HW prediction array"); + break; + default: + /* shouldn't be any more arguments */ + rrd_set_error("Unexpected extra argument for consolidation function %s", + rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam); + break; + } + break; + case 5: + /* If we are here, this must be a CF_HWPREDICT RRA. + * Specifies the index (1-based) of CF_SEASONAL array + * associated with this CF_HWPREDICT array. If this argument + * is missing, then the CF_SEASONAL, CF_DEVSEASONAL, CF_DEVPREDICT, + * CF_FAILURES. + * arrays are created automatically. */ + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt = + atoi(token) - 1; + break; + default: + /* should never get here */ + rrd_set_error("Unknown error"); + break; + } /* end switch */ + if (rrd_test_error()) + { + /* all errors are unrecoverable */ rrd_free(&rrd); - return (-1); + return (-1); + } + token = strtok(NULL,":"); + token_idx++; + } /* end while */ +#ifdef DEBUG + fprintf(stderr,"Creating RRA CF: %s, dep idx %lu, current idx %lu\n", + rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam, + rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt, + rrd.stat_head -> rra_cnt); +#endif + /* should we create CF_SEASONAL, CF_DEVSEASONAL, and CF_DEVPREDICT? */ + if (cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) == CF_HWPREDICT + && rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_dependent_rra_idx].u_cnt + == rrd.stat_head -> rra_cnt) + { +#ifdef DEBUG + fprintf(stderr,"Creating HW contingent RRAs\n"); +#endif + if (create_hw_contingent_rras(&rrd,period,hashed_name) == -1) { + rrd_free(&rrd); + return -1; + } } - + rrd.stat_head->rra_cnt++; } else { rrd_set_error("can't parse argument '%s'",argv[i]); rrd_free(&rrd); @@ -214,6 +406,75 @@ rrd_create(int argc, char **argv) return rrd_create_fn(argv[optind],&rrd); } +/* Create the CF_DEVPREDICT, CF_DEVSEASONAL, CF_SEASONAL, and CF_FAILURES RRAs + * associated with a CF_HWPREDICT RRA. */ +int +create_hw_contingent_rras(rrd_t *rrd, unsigned short period, unsigned long hashed_name) +{ + size_t old_size; + rra_def_t* current_rra; + + /* save index to CF_HWPREDICT */ + unsigned long hw_index = rrd -> stat_head -> rra_cnt; + /* advance the pointer */ + (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, + old_size+4*sizeof(rra_def_t)))==NULL) + { + rrd_set_error("allocating rrd.rra_def"); + return(-1); + } + /* clear memory */ + memset(&(rrd -> rra_def[rrd -> stat_head->rra_cnt]), 0, 4*sizeof(rra_def_t)); + + /* create the CF_SEASONAL RRA */ + current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]); + strcpy(current_rra -> cf_nam,"SEASONAL"); + current_rra -> row_cnt = period; + current_rra -> par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period; + current_rra -> pdp_cnt = 1; + current_rra -> par[RRA_seasonal_gamma].u_val = + rrd -> rra_def[hw_index].par[RRA_hw_alpha].u_val; + current_rra -> par[RRA_dependent_rra_idx].u_cnt = hw_index; + rrd -> rra_def[hw_index].par[RRA_dependent_rra_idx].u_cnt = rrd -> stat_head -> rra_cnt; + + /* create the CF_DEVSEASONAL RRA */ + (rrd -> stat_head -> rra_cnt)++; + current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]); + strcpy(current_rra -> cf_nam,"DEVSEASONAL"); + current_rra -> row_cnt = period; + current_rra -> par[RRA_seasonal_smooth_idx].u_cnt = hashed_name % period; + current_rra -> pdp_cnt = 1; + current_rra -> par[RRA_seasonal_gamma].u_val = + rrd -> rra_def[hw_index].par[RRA_hw_alpha].u_val; + current_rra -> par[RRA_dependent_rra_idx].u_cnt = hw_index; + + /* create the CF_DEVPREDICT RRA */ + (rrd -> stat_head -> rra_cnt)++; + current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]); + strcpy(current_rra -> cf_nam,"DEVPREDICT"); + current_rra -> row_cnt = (rrd -> rra_def[hw_index]).row_cnt; + current_rra -> pdp_cnt = 1; + current_rra -> par[RRA_dependent_rra_idx].u_cnt + = hw_index + 2; /* DEVSEASONAL */ + + /* create the CF_FAILURES RRA */ + (rrd -> stat_head -> rra_cnt)++; + current_rra = &(rrd -> rra_def[rrd -> stat_head -> rra_cnt]); + strcpy(current_rra -> cf_nam,"FAILURES"); + current_rra -> row_cnt = period; + current_rra -> pdp_cnt = 1; + current_rra -> par[RRA_delta_pos].u_val = 2.0; + current_rra -> par[RRA_delta_neg].u_val = 2.0; + current_rra -> par[RRA_failure_threshold].u_cnt = 7; + current_rra -> par[RRA_window_len].u_cnt = 9; + current_rra -> par[RRA_dependent_rra_idx].u_cnt = + hw_index + 2; /* DEVSEASONAL */ + return 0; +} + /* create and empty rrd file according to the specs given */ int @@ -266,21 +527,50 @@ rrd_create_fn(char *file_name, rrd_t *rrd) return(-1); } - /* can not be zero because we don't know nothing ... */ - rrd->cdp_prep->scratch[CDP_val].u_val = DNAN; - for(i=0; i < rrd->stat_head->rra_cnt; i++) { - - /* startup missing pdp count */ - rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt = - ((rrd->live_head->last_up - - rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt) - % (rrd->stat_head->pdp_step - * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step; - - for(ii=0; ii < rrd->stat_head->ds_cnt; ii++) { - fwrite( rrd->cdp_prep,sizeof(cdp_prep_t),1,rrd_file); - } + for(i=0; i < rrd->stat_head->rra_cnt; i++) { + switch (cf_conv(rrd->rra_def[i].cf_nam)) + { + case CF_HWPREDICT: + rrd->cdp_prep->scratch[CDP_hw_intercept].u_val = DNAN; + rrd->cdp_prep->scratch[CDP_hw_last_intercept].u_val = DNAN; + rrd->cdp_prep->scratch[CDP_hw_slope].u_val = DNAN; + rrd->cdp_prep->scratch[CDP_hw_last_slope].u_val = DNAN; + rrd->cdp_prep->scratch[CDP_null_count].u_cnt = 1; + rrd->cdp_prep->scratch[CDP_last_null_count].u_cnt = 1; + break; + case CF_SEASONAL: + case CF_DEVSEASONAL: + rrd->cdp_prep->scratch[CDP_hw_seasonal].u_val = DNAN; + rrd->cdp_prep->scratch[CDP_hw_last_seasonal].u_val = DNAN; + rrd->cdp_prep->scratch[CDP_init_seasonal].u_cnt = 1; + break; + case CF_FAILURES: + /* initialize violation history to 0 */ + for (ii = 0; ii < MAX_CDP_PAR_EN; ii++) + { + /* We can zero everything out, by setting u_val to the + * NULL address. Each array entry in scratch is 8 bytes + * (a double), but u_cnt only accessed 4 bytes (long) */ + rrd->cdp_prep->scratch[ii].u_val = 0.0; + } + break; + default: + /* can not be zero because we don't know anything ... */ + rrd->cdp_prep->scratch[CDP_val].u_val = DNAN; + /* startup missing pdp count */ + rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt = + ((rrd->live_head->last_up - + rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt) + % (rrd->stat_head->pdp_step + * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step; + break; + } + + for(ii=0; ii < rrd->stat_head->ds_cnt; ii++) + { + fwrite( rrd->cdp_prep,sizeof(cdp_prep_t),1,rrd_file); + } } /* now, we must make sure that the rest of the rrd @@ -292,13 +582,16 @@ rrd_create_fn(char *file_name, rrd_t *rrd) fclose(rrd_file); return(-1); } - - rrd->rra_ptr->cur_row = 0; - for(i=0; i stat_head->rra_cnt; i++) - fwrite( rrd->rra_ptr, - sizeof(rra_ptr_t), 1,rrd_file); - - + + /* changed this initialization to be consistent with + * rrd_restore. With the old value (0), the first update + * 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); + } /* write the empty data area */ for(i=0;