int rrd_create_fn(const char *file_name, rrd_t *rrd) { unsigned long i, ii; rrd_value_t *unknown; int unkn_cnt; rrd_file_t *rrd_file_dn; rrd_t rrd_dn; unsigned rrd_flags = RRD_READWRITE | RRD_CREAT; int ret = 0; 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_dn = rrd_open(file_name, rrd, rrd_flags, &ret)) == NULL) { rrd_free2(rrd); return ret; } if (rrd_write(rrd_file_dn, rrd->stat_head, sizeof(stat_head_t)) < 0){ rrd_free2(rrd); rrd_close(rrd_file_dn); return (-RRD_ERR_WRITE5); } rrd_write(rrd_file_dn, rrd->ds_def, sizeof(ds_def_t) * rrd->stat_head->ds_cnt); rrd_write(rrd_file_dn, rrd->rra_def, sizeof(rra_def_t) * rrd->stat_head->rra_cnt); rrd_write(rrd_file_dn, rrd->live_head, sizeof(live_head_t)); if ((rrd->pdp_prep = (pdp_prep_t*)calloc(1, sizeof(pdp_prep_t))) == NULL) { rrd_free2(rrd); rrd_close(rrd_file_dn); return (-RRD_ERR_ALLOC); } 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++) rrd_write(rrd_file_dn, rrd->pdp_prep, sizeof(pdp_prep_t)); if ((rrd->cdp_prep = (cdp_prep_t*)calloc(1, sizeof(cdp_prep_t))) == NULL) { rrd_free2(rrd); rrd_close(rrd_file_dn); return (-RRD_ERR_ALLOC); } for (i = 0; i < rrd->stat_head->rra_cnt; i++) { switch (cf_conv(rrd->rra_def[i].cf_nam)) { case CF_HWPREDICT: case CF_MHWPREDICT: init_hwpredict_cdp(rrd->cdp_prep); break; case CF_SEASONAL: case CF_DEVSEASONAL: init_seasonal_cdp(rrd->cdp_prep); 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++) { 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 = (rra_ptr_t*)calloc(1, sizeof(rra_ptr_t))) == NULL) { rrd_free2(rrd); rrd_close(rrd_file_dn); return -RRD_ERR_ALLOC; } /* 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_select_initial_row(rrd_file_dn, i, &rrd->rra_def[i]); rrd_write(rrd_file_dn, rrd->rra_ptr, sizeof(rra_ptr_t)); } /* write the empty data area */ if ((unknown = (rrd_value_t *) malloc(512 * sizeof(rrd_value_t))) == NULL) { rrd_free2(rrd); rrd_close(rrd_file_dn); return -RRD_ERR_ALLOC; } for (i = 0; i < 512; ++i) unknown[i] = DNAN; while (unkn_cnt > 0) { if(rrd_write(rrd_file_dn, unknown, sizeof(rrd_value_t) * min(unkn_cnt, 512)) < 0) { return -RRD_ERR_CREATE_WRITE; } unkn_cnt -= 512; } free(unknown); rrd_free2(rrd); if (rrd_close(rrd_file_dn) == -1) { return -RRD_ERR_CREATE_WRITE; } /* 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, &ret)) != NULL) { rrd_dontneed(rrd_file_dn, &rrd_dn); /* rrd_free(&rrd_dn); */ rrd_close(rrd_file_dn); } return ret; }
/* Reset aberrant behavior model coefficients, including intercept, slope, * seasonal, and seasonal deviation for the specified data source. */ void reset_aberrant_coefficients( rrd_t *rrd, rrd_file_t *rrd_file, unsigned long ds_idx) { unsigned long cdp_idx, rra_idx, i; unsigned long cdp_start, rra_start; rrd_value_t nan_buffer = DNAN; /* compute the offset for the cdp area */ cdp_start = sizeof(stat_head_t) + rrd->stat_head->ds_cnt * sizeof(ds_def_t) + rrd->stat_head->rra_cnt * sizeof(rra_def_t) + sizeof(live_head_t) + rrd->stat_head->ds_cnt * sizeof(pdp_prep_t); /* compute the offset for the first rra */ rra_start = cdp_start + (rrd->stat_head->ds_cnt) * (rrd->stat_head->rra_cnt) * sizeof(cdp_prep_t) + rrd->stat_head->rra_cnt * sizeof(rra_ptr_t); /* loop over the RRAs */ for (rra_idx = 0; rra_idx < rrd->stat_head->rra_cnt; rra_idx++) { cdp_idx = rra_idx * (rrd->stat_head->ds_cnt) + ds_idx; switch (cf_conv(rrd->rra_def[rra_idx].cf_nam)) { case CF_HWPREDICT: case CF_MHWPREDICT: init_hwpredict_cdp(&(rrd->cdp_prep[cdp_idx])); break; case CF_SEASONAL: case CF_DEVSEASONAL: /* don't use init_seasonal because it will reset burn-in, which * means different data sources will be calling for the smoother * at different times. */ rrd->cdp_prep[cdp_idx].scratch[CDP_hw_seasonal].u_val = DNAN; rrd->cdp_prep[cdp_idx].scratch[CDP_hw_last_seasonal].u_val = DNAN; /* move to first entry of data source for this rra */ rrd_seek(rrd_file, rra_start + ds_idx * sizeof(rrd_value_t), SEEK_SET); /* entries for the same data source are not contiguous, * temporal entries are contiguous */ for (i = 0; i < rrd->rra_def[rra_idx].row_cnt; ++i) { if (rrd_write(rrd_file, &nan_buffer, sizeof(rrd_value_t) * 1) != sizeof(rrd_value_t) * 1) { rrd_set_error ("reset_aberrant_coefficients: write failed data source %lu rra %s", ds_idx, rrd->rra_def[rra_idx].cf_nam); return; } rrd_seek(rrd_file, (rrd->stat_head->ds_cnt - 1) * sizeof(rrd_value_t), SEEK_CUR); } break; case CF_FAILURES: erase_violations(rrd, cdp_idx, rra_idx); break; default: break; } /* move offset to the next rra */ rra_start += rrd->rra_def[rra_idx].row_cnt * rrd->stat_head->ds_cnt * sizeof(rrd_value_t); } rrd_seek(rrd_file, cdp_start, SEEK_SET); if (rrd_write(rrd_file, rrd->cdp_prep, sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt) != (ssize_t) (sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) * (rrd->stat_head->ds_cnt))) { rrd_set_error("reset_aberrant_coefficients: cdp_prep write failed"); } }
int rrd_tune( int argc, char **argv) { rrd_t rrd; int matches; int optcnt = 0; long ds; char ds_nam[DS_NAM_SIZE]; char ds_new[DS_NAM_SIZE]; long heartbeat; double min = 0; double max = 0; char dst[DST_SIZE]; int rc = -1; int opt_newstep = -1; rrd_file_t *rrd_file = NULL; char *opt_daemon = NULL; char double_str[ 12 ]; const char *in_filename = NULL; struct option long_options[] = { {"heartbeat", required_argument, 0, 'h'}, {"minimum", required_argument, 0, 'i'}, {"maximum", required_argument, 0, 'a'}, {"data-source-type", required_argument, 0, 'd'}, {"data-source-rename", required_argument, 0, 'r'}, /* added parameter tuning options for aberrant behavior detection */ {"deltapos", required_argument, 0, 'p'}, {"deltaneg", required_argument, 0, 'n'}, {"window-length", required_argument, 0, 'w'}, {"failure-threshold", required_argument, 0, 'f'}, {"alpha", required_argument, 0, 'x'}, {"beta", required_argument, 0, 'y'}, {"gamma", required_argument, 0, 'z'}, {"gamma-deviation", required_argument, 0, 'v'}, {"smoothing-window", required_argument, 0, 's'}, {"smoothing-window-deviation", required_argument, 0, 'S'}, {"aberrant-reset", required_argument, 0, 'b'}, // integration of rrd_modify functionality. {"step", required_argument, 0, 't'}, /* unfortunately, '-d' is already taken */ {"daemon", required_argument, 0, 'D'}, {0, 0, 0, 0} }; optind = 0; opterr = 0; /* initialize getopt */ /* before we open the input RRD, we should flush it from any caching daemon, because we might totally rewrite it later on */ /* for this, we FIRST have to find the daemon, this means we must parse options twice... */ while (1) { int option_index = 0; int opt = getopt_long(argc, argv, "h:i:a:d:r:p:n:w:f:x:y:z:v:b:", long_options, &option_index); if (opt == EOF) break; switch (opt) { case 'D': if (opt_daemon != NULL) free (opt_daemon); opt_daemon = strdup (optarg); if (opt_daemon == NULL) { rrd_set_error ("strdup failed."); return (-1); } break; default: break; } } // connect to daemon (will take care of environment variable automatically) if (rrdc_connect(opt_daemon) != 0) { rrd_set_error("Cannot connect to daemon"); return 1; } if (opt_daemon) { free(opt_daemon); opt_daemon = NULL; } if (optind < 0 || optind >= argc) { // missing file name... rrd_set_error("missing file name"); goto done; } /* NOTE: getopt_long reorders argv and places all NON option arguments to the back, starting with optind. This means the file name has travelled to argv[optind] */ in_filename = argv[optind]; if (rrdc_is_any_connected()) { // is it a good idea to just ignore the error ???? rrdc_flush(in_filename); rrd_clear_error(); } optind = 0; opterr = 0; /* re-initialize getopt */ rrd_init(&rrd); rrd_file = rrd_open(in_filename, &rrd, RRD_READWRITE | RRD_READAHEAD | RRD_READVALUES); if (rrd_file == NULL) { goto done; } while (1) { int option_index = 0; int opt; unsigned int strtod_ret_val; opt = getopt_long(argc, argv, "h:i:a:d:r:p:n:w:f:x:y:z:v:b:", long_options, &option_index); if (opt == EOF) break; optcnt++; switch (opt) { case 'h': if ((matches = sscanf(optarg, DS_NAM_FMT ":%ld", ds_nam, &heartbeat)) != 2) { rrd_set_error("invalid arguments for heartbeat"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat; break; case 'i': matches = sscanf(optarg, DS_NAM_FMT ":%[0-9.e+-]", ds_nam, double_str); if( matches >= 1 ) { strtod_ret_val = rrd_strtodbl( double_str, NULL, &min, NULL ); } if ((matches < 1) || (strtod_ret_val != 2)) { rrd_set_error("invalid arguments for minimum ds value"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } if (matches == 1) min = DNAN; rrd.ds_def[ds].par[DS_min_val].u_val = min; break; case 'a': matches = sscanf(optarg, DS_NAM_FMT ":%[0-9.e+-]", ds_nam, double_str); if( matches >= 1 ) { strtod_ret_val = rrd_strtodbl( double_str, NULL, &max, NULL ); } if ((matches < 1 ) || (strtod_ret_val != 2)) { rrd_set_error("invalid arguments for maximum ds value"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } if (matches == 1) max = DNAN; rrd.ds_def[ds].par[DS_max_val].u_val = max; break; case 'd': if ((matches = sscanf(optarg, DS_NAM_FMT ":" DST_FMT, ds_nam, dst)) != 2) { rrd_set_error("invalid arguments for data source type"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } if ((int) dst_conv(dst) == -1) { goto done; } /* only reset when something is changed */ if (strncmp(rrd.ds_def[ds].dst, dst, DST_SIZE - 1) != 0) { strncpy(rrd.ds_def[ds].dst, dst, DST_SIZE - 1); rrd.ds_def[ds].dst[DST_SIZE - 1] = '\0'; rrd.pdp_prep[ds].last_ds[0] = 'U'; rrd.pdp_prep[ds].last_ds[1] = 'N'; rrd.pdp_prep[ds].last_ds[2] = 'K'; rrd.pdp_prep[ds].last_ds[3] = 'N'; rrd.pdp_prep[ds].last_ds[4] = '\0'; } break; case 'r': if ((matches = sscanf(optarg, DS_NAM_FMT ":" DS_NAM_FMT, ds_nam, ds_new)) != 2) { rrd_set_error("invalid arguments for data source type"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { goto done; } strncpy(rrd.ds_def[ds].ds_nam, ds_new, DS_NAM_SIZE - 1); rrd.ds_def[ds].ds_nam[DS_NAM_SIZE - 1] = '\0'; break; case 'p': if (set_deltaarg(&rrd, RRA_delta_pos, optarg)) { goto done; } break; case 'n': if (set_deltaarg(&rrd, RRA_delta_neg, optarg)) { goto done; } break; case 'f': if (set_windowarg(&rrd, RRA_failure_threshold, optarg)) { goto done; } break; case 'w': if (set_windowarg(&rrd, RRA_window_len, optarg)) { goto done; } break; case 'x': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_alpha, optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_alpha, optarg)) { goto done; } rrd_clear_error(); } break; case 'y': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_beta, optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_beta, optarg)) { goto done; } rrd_clear_error(); } break; case 'z': if (set_hwarg(&rrd, CF_SEASONAL, RRA_seasonal_gamma, optarg)) { goto done; } break; case 'v': if (set_hwarg(&rrd, CF_DEVSEASONAL, RRA_seasonal_gamma, optarg)) { goto done; } break; case 'b': if (sscanf(optarg, DS_NAM_FMT, ds_nam) != 1) { rrd_set_error("invalid argument for aberrant-reset"); goto done; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { /* ds_match handles it own errors */ goto done; } reset_aberrant_coefficients(&rrd, rrd_file, (unsigned long) ds); if (rrd_test_error()) { goto done; } break; case 's': if (atoi(rrd.stat_head->version) < atoi(RRD_VERSION4)) { strcpy(rrd.stat_head->version, RRD_VERSION4); /* smoothing_window causes Version 4 */ } if (set_hwsmootharg (&rrd, CF_SEASONAL, RRA_seasonal_smoothing_window, optarg)) { goto done; } break; case 'S': if (atoi(rrd.stat_head->version) < atoi(RRD_VERSION4)) { strcpy(rrd.stat_head->version, RRD_VERSION4); /* smoothing_window causes Version 4 */ } if (set_hwsmootharg (&rrd, CF_DEVSEASONAL, RRA_seasonal_smoothing_window, optarg)) { goto done; } break; case 't': opt_newstep = atoi(optarg); break; case 'D': // ignore, handled in previous argv parsing round break; case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); else rrd_set_error("unknown option '%s'", argv[optind - 1]); goto done; } } if (optcnt > 0) { rrd_seek(rrd_file, 0, SEEK_SET); rrd_write(rrd_file, rrd.stat_head, sizeof(stat_head_t) * 1); rrd_write(rrd_file, rrd.ds_def, sizeof(ds_def_t) * rrd.stat_head->ds_cnt); /* need to write rra_defs for RRA parameter changes */ rrd_write(rrd_file, rrd.rra_def, sizeof(rra_def_t) * rrd.stat_head->rra_cnt); } if (optind >= argc) { int i; for (i = 0; i < (int) rrd.stat_head->ds_cnt; i++) if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) { printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt, rrd.ds_def[i].par[DS_min_val].u_val, rrd.ds_def[i].par[DS_max_val].u_val); } else { char *buffer = NULL; rpn_compact2str((rpn_cdefds_t *) & (rrd.ds_def[i].par[DS_cdef]), rrd.ds_def, &buffer); printf("DS[%s] typ: %s\tcdef: %s\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, buffer); if (buffer) free(buffer); } } optind = handle_modify(&rrd, in_filename, argc, argv, optind + 1, opt_newstep); if (optind < 0) { goto done; } rc = 0; done: if (in_filename && rrdc_is_any_connected()) { // save any errors.... char *e = strdup(rrd_get_error()); // is it a good idea to just ignore the error ???? rrdc_forget(in_filename); rrd_clear_error(); if (e && *e) { rrd_set_error(e); } if (e) free(e); } if (rrd_file) { rrd_close(rrd_file); } rrd_free(&rrd); return rc; }
/* Smooth a periodic array with a moving average: equal weights and * length = 5% of the period. */ int apply_smoother( rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, rrd_file_t *rrd_file) { unsigned long i, j, k; unsigned long totalbytes; rrd_value_t *rrd_values; unsigned long row_length = rrd->stat_head->ds_cnt; unsigned long row_count = rrd->rra_def[rra_idx].row_cnt; unsigned long offset; FIFOqueue **buffers; rrd_value_t *working_average; rrd_value_t *rrd_values_cpy; rrd_value_t *baseline; if (atoi(rrd->stat_head->version) >= 4) { offset = floor(rrd->rra_def[rra_idx]. par[RRA_seasonal_smoothing_window]. u_val / 2 * row_count); } else { offset = floor(0.05 / 2 * row_count); } if (offset == 0) return 0; /* no smoothing */ /* allocate memory */ totalbytes = sizeof(rrd_value_t) * row_length * row_count; rrd_values = (rrd_value_t *) malloc(totalbytes); if (rrd_values == NULL) { rrd_set_error("apply smoother: memory allocation failure"); return -1; } /* rra_start is at the beginning of this rra */ if (rrd_seek(rrd_file, rra_start, SEEK_SET)) { rrd_set_error("seek to rra %d failed", rra_start); free(rrd_values); return -1; } /* could read all data in a single block, but we need to * check for NA values */ for (i = 0; i < row_count; ++i) { for (j = 0; j < row_length; ++j) { if (rrd_read (rrd_file, &(rrd_values[i * row_length + j]), sizeof(rrd_value_t) * 1) != (ssize_t) (sizeof(rrd_value_t) * 1)) { rrd_set_error("reading value failed: %s", rrd_strerror(errno)); } if (isnan(rrd_values[i * row_length + j])) { /* can't apply smoothing, still uninitialized values */ #ifdef DEBUG fprintf(stderr, "apply_smoother: NA detected in seasonal array: %ld %ld\n", i, j); #endif free(rrd_values); return 0; } } } /* allocate queues, one for each data source */ buffers = (FIFOqueue **) malloc(sizeof(FIFOqueue *) * row_length); for (i = 0; i < row_length; ++i) { queue_alloc(&(buffers[i]), 2 * offset + 1); } /* need working average initialized to 0 */ working_average = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t)); baseline = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t)); /* compute sums of the first 2*offset terms */ for (i = 0; i < 2 * offset; ++i) { k = MyMod(i - offset, row_count); for (j = 0; j < row_length; ++j) { queue_push(buffers[j], rrd_values[k * row_length + j]); working_average[j] += rrd_values[k * row_length + j]; } } /* as we are working through the value, we have to make sure to not double apply the smoothing after wrapping around. so best is to copy the rrd_values first */ rrd_values_cpy = (rrd_value_t *) calloc(row_length*row_count, sizeof(rrd_value_t)); memcpy(rrd_values_cpy,rrd_values,sizeof(rrd_value_t)*row_length*row_count); /* compute moving averages */ for (i = offset; i < row_count + offset; ++i) { for (j = 0; j < row_length; ++j) { k = MyMod(i, row_count); /* add a term to the sum */ working_average[j] += rrd_values_cpy[k * row_length + j]; queue_push(buffers[j], rrd_values_cpy[k * row_length + j]); /* reset k to be the center of the window */ k = MyMod(i - offset, row_count); /* overwrite rdd_values entry, the old value is already * saved in buffers */ rrd_values[k * row_length + j] = working_average[j] / (2 * offset + 1); baseline[j] += rrd_values[k * row_length + j]; /* remove a term from the sum */ working_average[j] -= queue_pop(buffers[j]); } } for (i = 0; i < row_length; ++i) { queue_dealloc(buffers[i]); baseline[i] /= row_count; } free(rrd_values_cpy); free(buffers); free(working_average); if (cf_conv(rrd->rra_def[rra_idx].cf_nam) == CF_SEASONAL) { rrd_value_t ( *init_seasonality) ( rrd_value_t seasonal_coef, rrd_value_t intercept); switch (cf_conv(rrd->rra_def[hw_dep_idx(rrd, rra_idx)].cf_nam)) { case CF_HWPREDICT: init_seasonality = hw_additive_init_seasonality; break; case CF_MHWPREDICT: init_seasonality = hw_multiplicative_init_seasonality; break; default: rrd_set_error("apply smoother: SEASONAL rra doesn't have " "valid dependency: %s", rrd->rra_def[hw_dep_idx(rrd, rra_idx)].cf_nam); return -1; } for (j = 0; j < row_length; ++j) { for (i = 0; i < row_count; ++i) { rrd_values[i * row_length + j] = init_seasonality(rrd_values[i * row_length + j], baseline[j]); } /* update the baseline coefficient, * first, compute the cdp_index. */ offset = hw_dep_idx(rrd, rra_idx) * row_length + j; (rrd->cdp_prep[offset]).scratch[CDP_hw_intercept].u_val += baseline[j]; } /* if we are not running on mmap, lets write stuff to disk now */ #ifndef HAVE_MMAP /* flush cdp to disk */ if (rrd_seek(rrd_file, sizeof(stat_head_t) + rrd->stat_head->ds_cnt * sizeof(ds_def_t) + rrd->stat_head->rra_cnt * sizeof(rra_def_t) + sizeof(live_head_t) + rrd->stat_head->ds_cnt * sizeof(pdp_prep_t), SEEK_SET)) { rrd_set_error("apply_smoother: seek to cdp_prep failed"); free(rrd_values); return -1; } if (rrd_write(rrd_file, rrd->cdp_prep, sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt) != (ssize_t) (sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) * (rrd->stat_head->ds_cnt))) { rrd_set_error("apply_smoother: cdp_prep write failed"); free(rrd_values); return -1; } #endif } /* endif CF_SEASONAL */ /* flush updated values to disk */ if (rrd_seek(rrd_file, rra_start, SEEK_SET)) { rrd_set_error("apply_smoother: seek to pos %d failed", rra_start); free(rrd_values); return -1; } /* write as a single block */ if (rrd_write (rrd_file, rrd_values, sizeof(rrd_value_t) * row_length * row_count) != (ssize_t) (sizeof(rrd_value_t) * row_length * row_count)) { rrd_set_error("apply_smoother: write failed to %lu", rra_start); free(rrd_values); return -1; } free(rrd_values); free(baseline); return 0; }
/* Smooth a periodic array with a moving average: equal weights and * length = 5% of the period. */ int apply_smoother( rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, rrd_file_t *rrd_file) { unsigned long i, j, k; unsigned long totalbytes; rrd_value_t *rrd_values; unsigned long row_length = rrd->stat_head->ds_cnt; unsigned long row_count = rrd->rra_def[rra_idx].row_cnt; unsigned long offset; FIFOqueue **buffers; rrd_value_t *working_average; rrd_value_t *baseline; int ret = 0; if (atoi(rrd->stat_head->version) >= 4) { offset = floor(rrd->rra_def[rra_idx]. par[RRA_seasonal_smoothing_window]. u_val / 2 * row_count); } else { offset = floor(0.05 / 2 * row_count); } if (offset == 0) return 0; /* no smoothing */ /* allocate memory */ totalbytes = sizeof(rrd_value_t) * row_length * row_count; rrd_values = (rrd_value_t *) malloc(totalbytes); if (rrd_values == NULL) { return -RRD_ERR_MALLOC5; } /* rra_start is at the beginning of this rra */ if (rrd_seek(rrd_file, rra_start, SEEK_SET)) { free(rrd_values); return -RRD_ERR_SEEK2; } /* could read all data in a single block, but we need to * check for NA values */ for (i = 0; i < row_count; ++i) { for (j = 0; j < row_length; ++j) { if (rrd_read (rrd_file, &(rrd_values[i * row_length + j]), sizeof(rrd_value_t) * 1) != (ssize_t) (sizeof(rrd_value_t) * 1)) { ret = -RRD_ERR_READ2; } if (isnan(rrd_values[i * row_length + j])) { /* can't apply smoothing, still uninitialized values */ #ifdef DEBUG fprintf(stderr, "apply_smoother: NA detected in seasonal array: %ld %ld\n", i, j); #endif free(rrd_values); return ret; } } } /* allocate queues, one for each data source */ buffers = (FIFOqueue **) malloc(sizeof(FIFOqueue *) * row_length); for (i = 0; i < row_length; ++i) { queue_alloc(&(buffers[i]), 2 * offset + 1); } /* need working average initialized to 0 */ working_average = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t)); baseline = (rrd_value_t *) calloc(row_length, sizeof(rrd_value_t)); /* compute sums of the first 2*offset terms */ for (i = 0; i < 2 * offset; ++i) { k = MyMod(i - offset, row_count); for (j = 0; j < row_length; ++j) { queue_push(buffers[j], rrd_values[k * row_length + j]); working_average[j] += rrd_values[k * row_length + j]; } } /* compute moving averages */ for (i = offset; i < row_count + offset; ++i) { for (j = 0; j < row_length; ++j) { k = MyMod(i, row_count); /* add a term to the sum */ working_average[j] += rrd_values[k * row_length + j]; queue_push(buffers[j], rrd_values[k * row_length + j]); /* reset k to be the center of the window */ k = MyMod(i - offset, row_count); /* overwrite rdd_values entry, the old value is already * saved in buffers */ rrd_values[k * row_length + j] = working_average[j] / (2 * offset + 1); baseline[j] += rrd_values[k * row_length + j]; /* remove a term from the sum */ working_average[j] -= queue_pop(buffers[j]); } } for (i = 0; i < row_length; ++i) { queue_dealloc(buffers[i]); baseline[i] /= row_count; } free(buffers); free(working_average); if (cf_conv(rrd->rra_def[rra_idx].cf_nam) == CF_SEASONAL) { rrd_value_t ( *init_seasonality) ( rrd_value_t seasonal_coef, rrd_value_t intercept); switch (cf_conv(rrd->rra_def[hw_dep_idx(rrd, rra_idx)].cf_nam)) { case CF_HWPREDICT: init_seasonality = hw_additive_init_seasonality; break; case CF_MHWPREDICT: init_seasonality = hw_multiplicative_init_seasonality; break; default: return -RRD_ERR_DEP1; } for (j = 0; j < row_length; ++j) { for (i = 0; i < row_count; ++i) { rrd_values[i * row_length + j] = init_seasonality(rrd_values[i * row_length + j], baseline[j]); } /* update the baseline coefficient, * first, compute the cdp_index. */ offset = hw_dep_idx(rrd, rra_idx) * row_length + j; (rrd->cdp_prep[offset]).scratch[CDP_hw_intercept].u_val += baseline[j]; } /* flush cdp to disk */ if (rrd_seek(rrd_file, sizeof(stat_head_t) + rrd->stat_head->ds_cnt * sizeof(ds_def_t) + rrd->stat_head->rra_cnt * sizeof(rra_def_t) + sizeof(live_head_t) + rrd->stat_head->ds_cnt * sizeof(pdp_prep_t), SEEK_SET)) { free(rrd_values); return -RRD_ERR_SEEK3; } if (rrd_write(rrd_file, rrd->cdp_prep, sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt) != (ssize_t) (sizeof(cdp_prep_t) * (rrd->stat_head->rra_cnt) * (rrd->stat_head->ds_cnt))) { free(rrd_values); return -RRD_ERR_WRITE1; } } /* endif CF_SEASONAL */ /* flush updated values to disk */ if (rrd_seek(rrd_file, rra_start, SEEK_SET)) { free(rrd_values); return -RRD_ERR_SEEK4; } /* write as a single block */ if (rrd_write (rrd_file, rrd_values, sizeof(rrd_value_t) * row_length * row_count) != (ssize_t) (sizeof(rrd_value_t) * row_length * row_count)) { free(rrd_values); return -RRD_ERR_WRITE2; } free(rrd_values); free(baseline); return 0; }
int rrd_restore(int argc, char **argv) { rrd_t rrd; char *buf; char rc = 0; char force_overwrite = 0; /* init rrd clean */ optind = 0; opterr = 0; /* initialize getopt */ rrd_init(&rrd); if (argc<3) { rrd_set_error("usage rrdtool %s [--range-check/-r] [--force-overwrite/-f] file.xml file.rrd",argv[0]); return -1; } while (1) { static struct option long_options[] = { {"range-check", required_argument, 0, 'r'}, {"force-overwrite", required_argument, 0, 'f'}, {0,0,0,0} }; int option_index = 0; int opt; opt = getopt_long(argc, argv, "r:f", long_options, &option_index); if (opt == EOF) break; switch(opt) { case 'r': rc=1; break; case 'f': force_overwrite=1; break; default: rrd_set_error("usage rrdtool %s [--range-check|-r] [--force-overwrite/-f] file.xml file.rrd",argv[0]); return -1; break; } } if (readfile(argv[optind],&buf,0)==-1){ return -1; } if (xml2rrd(buf,&rrd,rc)==-1) { rrd_free(&rrd); free(buf); return -1; } free(buf); if(rrd_write(argv[optind+1],&rrd,force_overwrite)==-1){ rrd_free(&rrd); return -1; }; rrd_free(&rrd); return 0; }
int rrd_resize( int argc, char **argv) { char *infilename, outfilename[11] = "resize.rrd"; rrd_t rrdold, rrdnew; rrd_value_t buffer; int version; unsigned long l, rra; long modify; unsigned long target_rra; int grow = 0, shrink = 0; char *endptr; rrd_file_t *rrd_file, *rrd_out_file; infilename = argv[1]; if (!strcmp(infilename, "resize.rrd")) { rrd_set_error("resize.rrd is a reserved name"); return (-1); } if (argc != 5) { rrd_set_error("wrong number of parameters"); return (-1); } target_rra = strtol(argv[2], &endptr, 0); if (!strcmp(argv[3], "GROW")) grow = 1; else if (!strcmp(argv[3], "SHRINK")) shrink = 1; else { rrd_set_error("I can only GROW or SHRINK"); return (-1); } modify = strtol(argv[4], &endptr, 0); if ((modify < 1)) { rrd_set_error("Please grow or shrink with at least 1 row"); return (-1); } if (shrink) modify = -modify; rrd_init(&rrdold); rrd_file = rrd_open(infilename, &rrdold, RRD_READWRITE | RRD_COPY); if (rrd_file == NULL) { rrd_free(&rrdold); return (-1); } if (rrd_lock(rrd_file) != 0) { rrd_set_error("could not lock original RRD"); rrd_free(&rrdold); rrd_close(rrd_file); return (-1); } if (target_rra >= rrdold.stat_head->rra_cnt) { rrd_set_error("no such RRA in this RRD"); rrd_free(&rrdold); rrd_close(rrd_file); return (-1); } if (modify < 0) if ((long) rrdold.rra_def[target_rra].row_cnt <= -modify) { rrd_set_error("This RRA is not that big"); rrd_free(&rrdold); rrd_close(rrd_file); return (-1); } rrd_init(&rrdnew); /* These need to be initialised before calling rrd_open() with the RRD_CREATE flag */ if ((rrdnew.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) { rrd_set_error("allocating stat_head for new RRD"); rrd_free(&rrdold); rrd_close(rrd_file); return (-1); } memcpy(rrdnew.stat_head,rrdold.stat_head,sizeof(stat_head_t)); if ((rrdnew.rra_def = (rra_def_t *)malloc(sizeof(rra_def_t) * rrdold.stat_head->rra_cnt)) == NULL) { rrd_set_error("allocating rra_def for new RRD"); rrd_free(&rrdnew); rrd_free(&rrdold); rrd_close(rrd_file); return (-1); } memcpy(rrdnew.rra_def,rrdold.rra_def,sizeof(rra_def_t) * rrdold.stat_head->rra_cnt); /* Set this so that the file will be created with the correct size */ rrdnew.rra_def[target_rra].row_cnt += modify; rrd_out_file = rrd_open(outfilename, &rrdnew, RRD_READWRITE | RRD_CREAT); if (rrd_out_file == NULL) { rrd_set_error("Can't create '%s': %s", outfilename, rrd_strerror(errno)); rrd_free(&rrdnew); rrd_free(&rrdold); rrd_close(rrd_file); return (-1); } if (rrd_lock(rrd_out_file) != 0) { rrd_set_error("could not lock new RRD"); rrd_free(&rrdnew); rrd_free(&rrdold); rrd_close(rrd_file); rrd_close(rrd_out_file); return (-1); } /*XXX: do one write for those parts of header that are unchanged */ if ((rrdnew.rra_ptr = (rra_ptr_t *)malloc(sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt)) == NULL) { rrd_set_error("allocating rra_ptr for new RRD"); rrd_free(&rrdnew); rrd_free(&rrdold); rrd_close(rrd_file); rrd_close(rrd_out_file); return (-1); } /* Put this back the way it was so that the rest of the algorithm below remains unchanged, it will be corrected later */ rrdnew.rra_def[target_rra].row_cnt -= modify; rrdnew.ds_def = rrdold.ds_def; rrdnew.live_head = rrdold.live_head; rrdnew.pdp_prep = rrdold.pdp_prep; rrdnew.cdp_prep = rrdold.cdp_prep; memcpy(rrdnew.rra_ptr,rrdold.rra_ptr,sizeof(rra_ptr_t) * rrdold.stat_head->rra_cnt); version = atoi(rrdold.stat_head->version); switch (version) { case 4: break; case 3: break; case 1: rrdnew.stat_head->version[3] = '3'; break; default: rrd_set_error("Do not know how to handle RRD version %s", rrdold.stat_head->version); rrdnew.ds_def = NULL; rrdnew.live_head = NULL; rrdnew.pdp_prep = NULL; rrdnew.cdp_prep = NULL; rrd_free(&rrdnew); rrd_free(&rrdold); rrd_close(rrd_file); rrd_close(rrd_out_file); return (-1); break; } /* XXX: Error checking? */ rrd_write(rrd_out_file, rrdnew.stat_head, sizeof(stat_head_t) * 1); rrd_write(rrd_out_file, rrdnew.ds_def, sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt); rrd_write(rrd_out_file, rrdnew.rra_def, sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt); rrd_write(rrd_out_file, rrdnew.live_head, sizeof(live_head_t) * 1); rrd_write(rrd_out_file, rrdnew.pdp_prep, sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt); rrd_write(rrd_out_file, rrdnew.cdp_prep, sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt * rrdnew.stat_head->rra_cnt); rrd_write(rrd_out_file, rrdnew.rra_ptr, sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt); /* Move the CDPs from the old to the new database. ** This can be made (much) faster but isn't worth the effort. Clarity ** is much more important. */ /* Move data in unmodified RRAs */ l = 0; for (rra = 0; rra < target_rra; rra++) { l += rrdnew.stat_head->ds_cnt * rrdnew.rra_def[rra].row_cnt; } while (l > 0) { rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1); rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); l--; } /* Move data in this RRA, either removing or adding some rows */ if (modify > 0) { /* Adding extra rows; insert unknown values just after the ** current row number. */ l = rrdnew.stat_head->ds_cnt * (rrdnew.rra_ptr[target_rra].cur_row + 1); while (l > 0) { rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1); rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); l--; } buffer = DNAN; l = rrdnew.stat_head->ds_cnt * modify; while (l > 0) { rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); l--; } } else { /* Removing rows. Normally this would be just after the cursor ** however this may also mean that we wrap to the beginning of ** the array. */ signed long int remove_end = 0; remove_end = (rrdnew.rra_ptr[target_rra].cur_row - modify) % rrdnew.rra_def[target_rra].row_cnt; if (remove_end <= (signed long int) rrdnew.rra_ptr[target_rra].cur_row) { while (remove_end >= 0) { rrd_seek(rrd_file, sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt, SEEK_CUR); rrdnew.rra_ptr[target_rra].cur_row--; rrdnew.rra_def[target_rra].row_cnt--; remove_end--; modify++; } remove_end = rrdnew.rra_def[target_rra].row_cnt - 1; } for (l = 0; l <= rrdnew.rra_ptr[target_rra].cur_row; l++) { unsigned int tmp; for (tmp = 0; tmp < rrdnew.stat_head->ds_cnt; tmp++) { rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1); rrd_write(rrd_out_file, &buffer, sizeof(rrd_value_t) * 1); } } while (modify < 0) { rrd_seek(rrd_file, sizeof(rrd_value_t) * rrdnew.stat_head->ds_cnt, SEEK_CUR); rrdnew.rra_def[target_rra].row_cnt--; modify++; } } /* Move the rest of the CDPs */ while (1) { ssize_t b_read; if ((b_read=rrd_read(rrd_file, &buffer, sizeof(rrd_value_t) * 1)) <= 0) break; if(rrd_out_file->pos+b_read > rrd_out_file->file_len) { fprintf(stderr,"WARNING: ignoring last %zu bytes\nWARNING: if you see this message multiple times for a single file you're in trouble\n", b_read); continue; } rrd_write(rrd_out_file, &buffer, b_read); } rrdnew.rra_def[target_rra].row_cnt += modify; rrd_seek(rrd_out_file, sizeof(stat_head_t) + sizeof(ds_def_t) * rrdnew.stat_head->ds_cnt, SEEK_SET); rrd_write(rrd_out_file, rrdnew.rra_def, sizeof(rra_def_t) * rrdnew.stat_head->rra_cnt); rrd_seek(rrd_out_file, sizeof(live_head_t), SEEK_CUR); rrd_seek(rrd_out_file, sizeof(pdp_prep_t) * rrdnew.stat_head->ds_cnt, SEEK_CUR); rrd_seek(rrd_out_file, sizeof(cdp_prep_t) * rrdnew.stat_head->ds_cnt * rrdnew.stat_head->rra_cnt, SEEK_CUR); rrd_write(rrd_out_file, rrdnew.rra_ptr, sizeof(rra_ptr_t) * rrdnew.stat_head->rra_cnt); rrd_close(rrd_file); rrd_close(rrd_out_file); rrd_free(&rrdold); rrdnew.ds_def = NULL; rrdnew.live_head = NULL; rrdnew.pdp_prep = NULL; rrdnew.cdp_prep = NULL; rrd_free(&rrdnew); return (0); }
int rrd_tune( int argc, char **argv) { rrd_t rrd; int matches; int optcnt = 0; long ds; char ds_nam[DS_NAM_SIZE]; char ds_new[DS_NAM_SIZE]; long heartbeat; double min; double max; char dst[DST_SIZE]; rrd_file_t *rrd_file; struct option long_options[] = { {"heartbeat", required_argument, 0, 'h'}, {"minimum", required_argument, 0, 'i'}, {"maximum", required_argument, 0, 'a'}, {"data-source-type", required_argument, 0, 'd'}, {"data-source-rename", required_argument, 0, 'r'}, /* added parameter tuning options for aberrant behavior detection */ {"deltapos", required_argument, 0, 'p'}, {"deltaneg", required_argument, 0, 'n'}, {"window-length", required_argument, 0, 'w'}, {"failure-threshold", required_argument, 0, 'f'}, {"alpha", required_argument, 0, 'x'}, {"beta", required_argument, 0, 'y'}, {"gamma", required_argument, 0, 'z'}, {"gamma-deviation", required_argument, 0, 'v'}, {"smoothing-window", required_argument, 0, 's'}, {"smoothing-window-deviation", required_argument, 0, 'S'}, {"aberrant-reset", required_argument, 0, 'b'}, {0, 0, 0, 0} }; optind = 0; opterr = 0; /* initialize getopt */ rrd_init(&rrd); rrd_file = rrd_open(argv[1], &rrd, RRD_READWRITE); if (rrd_file == NULL) { rrd_free(&rrd); return -1; } while (1) { int option_index = 0; int opt; char *old_locale = ""; opt = getopt_long(argc, argv, "h:i:a:d:r:p:n:w:f:x:y:z:v:b:", long_options, &option_index); if (opt == EOF) break; optcnt++; switch (opt) { case 'h': old_locale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); if ((matches = sscanf(optarg, DS_NAM_FMT ":%ld", ds_nam, &heartbeat)) != 2) { rrd_set_error("invalid arguments for heartbeat"); rrd_free(&rrd); rrd_close(rrd_file); setlocale(LC_NUMERIC, old_locale); return -1; } setlocale(LC_NUMERIC, old_locale); if ((ds = ds_match(&rrd, ds_nam)) == -1) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } rrd.ds_def[ds].par[DS_mrhb_cnt].u_cnt = heartbeat; break; case 'i': old_locale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); if ((matches = sscanf(optarg, DS_NAM_FMT ":%lf", ds_nam, &min)) < 1) { rrd_set_error("invalid arguments for minimum ds value"); rrd_free(&rrd); rrd_close(rrd_file); setlocale(LC_NUMERIC, old_locale); return -1; } setlocale(LC_NUMERIC, old_locale); if ((ds = ds_match(&rrd, ds_nam)) == -1) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } if (matches == 1) min = DNAN; rrd.ds_def[ds].par[DS_min_val].u_val = min; break; case 'a': old_locale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); if ((matches = sscanf(optarg, DS_NAM_FMT ":%lf", ds_nam, &max)) < 1) { rrd_set_error("invalid arguments for maximum ds value"); rrd_free(&rrd); rrd_close(rrd_file); setlocale(LC_NUMERIC, old_locale); return -1; } setlocale(LC_NUMERIC, old_locale); if ((ds = ds_match(&rrd, ds_nam)) == -1) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } if (matches == 1) max = DNAN; rrd.ds_def[ds].par[DS_max_val].u_val = max; break; case 'd': if ((matches = sscanf(optarg, DS_NAM_FMT ":" DST_FMT, ds_nam, dst)) != 2) { rrd_set_error("invalid arguments for data source type"); rrd_free(&rrd); rrd_close(rrd_file); return -1; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } if ((int) dst_conv(dst) == -1) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } /* only reset when something is changed */ if (strncmp(rrd.ds_def[ds].dst, dst, DST_SIZE - 1) != 0) { strncpy(rrd.ds_def[ds].dst, dst, DST_SIZE - 1); rrd.ds_def[ds].dst[DST_SIZE - 1] = '\0'; rrd.pdp_prep[ds].last_ds[0] = 'U'; rrd.pdp_prep[ds].last_ds[1] = 'N'; rrd.pdp_prep[ds].last_ds[2] = 'K'; rrd.pdp_prep[ds].last_ds[3] = 'N'; rrd.pdp_prep[ds].last_ds[4] = '\0'; } break; case 'r': if ((matches = sscanf(optarg, DS_NAM_FMT ":" DS_NAM_FMT, ds_nam, ds_new)) != 2) { rrd_set_error("invalid arguments for data source type"); rrd_free(&rrd); rrd_close(rrd_file); return -1; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } strncpy(rrd.ds_def[ds].ds_nam, ds_new, DS_NAM_SIZE - 1); rrd.ds_def[ds].ds_nam[DS_NAM_SIZE - 1] = '\0'; break; case 'p': if (set_deltaarg(&rrd, RRA_delta_pos, optarg)) { rrd_free(&rrd); return -1; } break; case 'n': if (set_deltaarg(&rrd, RRA_delta_neg, optarg)) { rrd_free(&rrd); return -1; } break; case 'f': if (set_windowarg(&rrd, RRA_failure_threshold, optarg)) { rrd_free(&rrd); return -1; } break; case 'w': if (set_windowarg(&rrd, RRA_window_len, optarg)) { rrd_free(&rrd); return -1; } break; case 'x': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_alpha, optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_alpha, optarg)) { rrd_free(&rrd); return -1; } rrd_clear_error(); } break; case 'y': if (set_hwarg(&rrd, CF_HWPREDICT, RRA_hw_beta, optarg)) { if (set_hwarg(&rrd, CF_MHWPREDICT, RRA_hw_beta, optarg)) { rrd_free(&rrd); return -1; } rrd_clear_error(); } break; case 'z': if (set_hwarg(&rrd, CF_SEASONAL, RRA_seasonal_gamma, optarg)) { rrd_free(&rrd); return -1; } break; case 'v': if (set_hwarg(&rrd, CF_DEVSEASONAL, RRA_seasonal_gamma, optarg)) { rrd_free(&rrd); return -1; } break; case 'b': if (sscanf(optarg, DS_NAM_FMT, ds_nam) != 1) { rrd_set_error("invalid argument for aberrant-reset"); rrd_free(&rrd); rrd_close(rrd_file); return -1; } if ((ds = ds_match(&rrd, ds_nam)) == -1) { /* ds_match handles it own errors */ rrd_free(&rrd); rrd_close(rrd_file); return -1; } reset_aberrant_coefficients(&rrd, rrd_file, (unsigned long) ds); if (rrd_test_error()) { rrd_free(&rrd); rrd_close(rrd_file); return -1; } break; case 's': strcpy(rrd.stat_head->version, RRD_VERSION); /* smoothing_window causes Version 4 */ if (set_hwsmootharg (&rrd, CF_SEASONAL, RRA_seasonal_smoothing_window, optarg)) { rrd_free(&rrd); return -1; } break; case 'S': strcpy(rrd.stat_head->version, RRD_VERSION); /* smoothing_window causes Version 4 */ if (set_hwsmootharg (&rrd, CF_DEVSEASONAL, RRA_seasonal_smoothing_window, optarg)) { rrd_free(&rrd); return -1; } break; case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); else rrd_set_error("unknown option '%s'", argv[optind - 1]); rrd_free(&rrd); rrd_close(rrd_file); return -1; } } if (optcnt > 0) { rrd_seek(rrd_file, 0, SEEK_SET); rrd_write(rrd_file, rrd.stat_head, sizeof(stat_head_t) * 1); rrd_write(rrd_file, rrd.ds_def, sizeof(ds_def_t) * rrd.stat_head->ds_cnt); /* need to write rra_defs for RRA parameter changes */ rrd_write(rrd_file, rrd.rra_def, sizeof(rra_def_t) * rrd.stat_head->rra_cnt); } else { int i; for (i = 0; i < (int) rrd.stat_head->ds_cnt; i++) if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) { printf("DS[%s] typ: %s\thbt: %ld\tmin: %1.4f\tmax: %1.4f\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt, rrd.ds_def[i].par[DS_min_val].u_val, rrd.ds_def[i].par[DS_max_val].u_val); } else { char *buffer = NULL; rpn_compact2str((rpn_cdefds_t *) & (rrd.ds_def[i].par[DS_cdef]), rrd.ds_def, &buffer); printf("DS[%s] typ: %s\tcdef: %s\n", rrd.ds_def[i].ds_nam, rrd.ds_def[i].dst, buffer); free(buffer); } } rrd_close(rrd_file); rrd_free(&rrd); return 0; }