示例#1
0
文件: rrd_xport.c 项目: blair/orca
/* mostly rrd_graph(), just pushed a bit here and stretched a bit there */
int
rrd_xport(int argc, char **argv, int *xsize,
          time_t         *start,
          time_t         *end,        /* which time frame do you want ?
				       * will be changed to represent reality */
          unsigned long  *step,       /* which stepsize do you want?
				       * will be changed to represent reality */
          unsigned long  *col_cnt,    /* number of data columns in the result */
          char           ***legend_v, /* legend entries */
          rrd_value_t    **data)      /* two dimensional array containing the data */

{
    image_desc_t   im;
    int            i;
    long           long_tmp;
    time_t	   start_tmp=0,end_tmp=0;
    char           symname[100];
    long           scancount;
    struct rrd_time_value start_tv, end_tv;
    char           *parsetime_error = NULL;

    parsetime("end-24h", &start_tv);
    parsetime("now", &end_tv);

    /* use the default values from rrd_graph.c */
    im.xlab_user.minsec = -1;
    im.xgif=0;
    im.ygif=0;
    im.xsize = 400;
    im.ysize = 100;
    im.step = 0;
    im.ylegend[0] = '\0';
    im.title[0] = '\0';
    im.minval = DNAN;
    im.maxval = DNAN;
    im.interlaced = 0;
    im.unitsexponent= 9999;
    im.unitslength= 9;
    im.extra_flags= 0;
    im.rigid = 0;
    im.imginfo = NULL;
    im.lazy = 0;
    im.logarithmic = 0;
    im.ygridstep = DNAN;
    im.draw_x_grid = 1;
    im.draw_y_grid = 1;
    im.base = 1000;
    im.prt_c = 0;
    im.gdes_c = 0;
    im.gdes = NULL;
    im.imgformat = IF_GIF; /* we default to GIF output */

    while (1) {
        static struct option long_options[] =
        {
            {"start",      required_argument, 0,  's'},
            {"end",        required_argument, 0,  'e'},
            {"maxrows",    required_argument, 0,  'm'},
            {"step",       required_argument, 0,   261},
            {0,0,0,0}
        };
        int option_index = 0;
        int opt;

        opt = getopt_long(argc, argv, "s:e:m:",
                          long_options, &option_index);

        if (opt == EOF)
            break;

        switch(opt) {
        case 261:
            im.step =  atoi(optarg);
            break;
        case 's':
            if ((parsetime_error = parsetime(optarg, &start_tv))) {
                rrd_set_error( "start time: %s", parsetime_error );
                return -1;
            }
            break;
        case 'e':
            if ((parsetime_error = parsetime(optarg, &end_tv))) {
                rrd_set_error( "end time: %s", parsetime_error );
                return -1;
            }
            break;
        case 'm':
            long_tmp = atol(optarg);
            if (long_tmp < 10) {
                rrd_set_error("maxrows below 10 rows");
                return -1;
            }
            im.xsize = long_tmp;
            break;

        case '?':
            if (optopt != 0)
                rrd_set_error("unknown option '%c'", optopt);
            else
                rrd_set_error("unknown option '%s'",argv[optind-1]);
            return -1;
        }
    }

    /*
    if (optind >= argc) {
       rrd_set_error("missing filename");
       return -1;
    }
    */

    if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1) {
        return -1;
    }

    if (start_tmp < 3600*24*365*10) {
        rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
        return -1;
    }

    if (end_tmp < start_tmp) {
        rrd_set_error("start (%ld) should be less than end (%ld)",
                      start_tmp, end_tmp);
        return -1;
    }

    im.start = start_tmp;
    im.end = end_tmp;


    for(i=optind; i<argc; i++) {
        int   argstart=0;
        int   strstart=0;
        char  varname[30],*rpnex;
        gdes_alloc(&im);
        if(sscanf(argv[i],"%10[A-Z0-9]:%n",symname,&argstart)==1) {
            if((im.gdes[im.gdes_c-1].gf=gf_conv(symname))==-1) {
                im_free(&im);
                rrd_set_error("unknown function '%s'",symname);
                return -1;
            }
        } else {
            rrd_set_error("can't parse '%s'",argv[i]);
            im_free(&im);
            return -1;
        }

        switch(im.gdes[im.gdes_c-1].gf) {
        case GF_CDEF:
            if((rpnex = malloc(strlen(&argv[i][argstart])*sizeof(char)))==NULL) {
                rrd_set_error("malloc for CDEF");
                return -1;
            }
            if(sscanf(
                        &argv[i][argstart],
                        DEF_NAM_FMT "=%[^: ]",
                        im.gdes[im.gdes_c-1].vname,
                        rpnex) != 2) {
                im_free(&im);
                free(rpnex);
                rrd_set_error("can't parse CDEF '%s'",&argv[i][argstart]);
                return -1;
            }
            /* checking for duplicate DEF CDEFS */
            if(find_var(&im,im.gdes[im.gdes_c-1].vname) != -1) {
                im_free(&im);
                rrd_set_error("duplicate variable '%s'",
                              im.gdes[im.gdes_c-1].vname);
                return -1;
            }
            if((im.gdes[im.gdes_c-1].rpnp = str2rpn(&im,rpnex))== NULL) {
                rrd_set_error("invalid rpn expression '%s'", rpnex);
                im_free(&im);
                return -1;
            }
            free(rpnex);
            break;
        case GF_DEF:
            if (sscanf(
                        &argv[i][argstart],
                        DEF_NAM_FMT "=%n",
                        im.gdes[im.gdes_c-1].vname,
                        &strstart)== 1 && strstart) { /* is the = did not match %n returns 0 */
                if(sscanf(&argv[i][argstart
                                   +strstart
                                   +scan_for_col(&argv[i][argstart+strstart],
                                                 MAXPATH,im.gdes[im.gdes_c-1].rrd)],
                          ":" DS_NAM_FMT ":" CF_NAM_FMT,
                          im.gdes[im.gdes_c-1].ds_nam,
                          symname) != 2) {
                    im_free(&im);
                    rrd_set_error("can't parse DEF '%s' -2",&argv[i][argstart]);
                    return -1;
                }
            } else {
                im_free(&im);
                rrd_set_error("can't parse DEF '%s'",&argv[i][argstart]);
                return -1;
            }

            /* checking for duplicate DEF CDEFS */
            if (find_var(&im,im.gdes[im.gdes_c-1].vname) != -1) {
                im_free(&im);
                rrd_set_error("duplicate variable '%s'",
                              im.gdes[im.gdes_c-1].vname);
                return -1;
            }
            if((im.gdes[im.gdes_c-1].cf=cf_conv(symname))==-1) {
                im_free(&im);
                rrd_set_error("unknown cf '%s'",symname);
                return -1;
            }
            break;
        case GF_XPORT:
            if((scancount=sscanf(
                              &argv[i][argstart],
                              "%29[^:]:%n",
                              varname,
                              &strstart))>=1) {
                if(strstart <= 0) {
                    im.gdes[im.gdes_c-1].legend[0] = '\0';
                } else {
                    scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend);
                }
                if((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname))==-1) {
                    im_free(&im);
                    rrd_set_error("unknown variable '%s'",varname);
                    return -1;
                }
            } else {
                im_free(&im);
                rrd_set_error("can't parse '%s'",&argv[i][argstart]);
                return -1;
            }
            break;
        default:
            break;
        }

    }

    if (im.gdes_c == 0) {
        rrd_set_error("can't make a graph without contents");
        im_free(&im);
        return(-1);
    }

    if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1) {
        im_free(&im);
        return -1;
    }

    im_free(&im);
    return 0;
}
/* #define DEBUG */
int rrd_create_r(
    const char *filename,
    unsigned long pdp_step,
    time_t last_up,
    int argc,
    const char **argv)
{
    rrd_t     rrd;
    long      i;
    int       offset;
    char     *token;
    char      dummychar1[2], dummychar2[2];
    unsigned short token_idx, error_flag, period = 0;
    unsigned long hashed_name;

    /* init rrd clean */
    rrd_init(&rrd);
    /* static header */
    if ((rrd.stat_head = (stat_head_t*)calloc(1, sizeof(stat_head_t))) == NULL) {
        rrd_set_error("allocating rrd.stat_head");
        rrd_free2(&rrd);
        return (-1);
    }

    /* live header */
    if ((rrd.live_head = (live_head_t*)calloc(1, sizeof(live_head_t))) == NULL) {
        rrd_set_error("allocating rrd.live_head");
        rrd_free2(&rrd);
        return (-1);
    }

    /* set some defaults */
    strcpy(rrd.stat_head->cookie, RRD_COOKIE);
    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 */
    rrd.stat_head->pdp_step = pdp_step; /* 5 minute default */

    /* a default value */
    rrd.ds_def = NULL;
    rrd.rra_def = NULL;

    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(filename);
    for (i = 0; i < argc; i++) {
        unsigned int ii;

        if (strncmp(argv[i], "DS:", 3) == 0) {
            size_t    old_size = sizeof(ds_def_t) * (rrd.stat_head->ds_cnt);

            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_free2(&rrd);
                return (-1);
            }
            memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
            /* extract the name and type */
            switch (sscanf(&argv[i][3],
                           DS_NAM_FMT "%1[:]" DST_FMT "%1[:]%n",
                           rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
                           dummychar1,
                           rrd.ds_def[rrd.stat_head->ds_cnt].dst,
                           dummychar2, &offset)) {
            case 0:
            case 1:
                rrd_set_error("Invalid DS name");
                break;
            case 2:
            case 3:
                rrd_set_error("Invalid DS type");
                break;
            case 4:    /* (%n may or may not be counted) */
            case 5:    /* check for duplicate datasource names */
                for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++)
                    if (strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
                               rrd.ds_def[ii].ds_nam) == 0)
                        rrd_set_error("Duplicate DS name: %s",
                                      rrd.ds_def[ii].ds_nam);
                /* DS_type may be valid or not. Checked later */
                break;
            default:
                rrd_set_error("invalid DS format");
            }
            if (rrd_test_error()) {
                rrd_free2(&rrd);
                return -1;
            }

            /* parse the remainder of the arguments */
            switch (dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst)) {
            case DST_COUNTER:
            case DST_ABSOLUTE:
            case DST_GAUGE:
            case DST_DERIVE:
                parseGENERIC_DS(&argv[i][offset + 3], &rrd,
                                rrd.stat_head->ds_cnt);
                break;
            case DST_CDEF:
                parseCDEF_DS(&argv[i][offset + 3], &rrd,
                             rrd.stat_head->ds_cnt);
                break;
            default:
                rrd_set_error("invalid DS type specified");
                break;
            }

            if (rrd_test_error()) {
                rrd_free2(&rrd);
                return -1;
            }
            rrd.stat_head->ds_cnt++;
        } else if (strncmp(argv[i], "RRA:", 4) == 0) {
            char     *argvcopy;
            char     *tokptr = "";
            int       cf_id = -1;
            size_t    old_size = sizeof(rra_def_t) * (rrd.stat_head->rra_cnt);
            int       row_cnt;
            int       token_min = 4;
            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_free2(&rrd);
                return (-1);
            }
            memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0,
                   sizeof(rra_def_t));

            argvcopy = strdup(argv[i]);
            token = strtok_r(&argvcopy[4], ":", &tokptr);
            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");
                    cf_id = cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam);
                    switch (cf_id) {
                    case CF_MHWPREDICT:
                        strcpy(rrd.stat_head->version, RRD_VERSION);    /* MHWPREDICT causes Version 4 */
                    case CF_HWPREDICT:
                        token_min = 5;
                        /* 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;
                        break;
                    case CF_DEVSEASONAL:
                        token_min = 3;
                    case CF_SEASONAL:
                        if (cf_id == CF_SEASONAL){
                           token_min = 4;
                        }
                        /* 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:
                        if (cf_id == CF_DEVPREDICT){
                           token_min = 3;
                        }
                        rrd.rra_def[rrd.stat_head->rra_cnt].
                            par[RRA_dependent_rra_idx].u_cnt = -1;
                        break;
                    case CF_FAILURES:
                        token_min = 5;
                        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;
                    }
                    /* 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_MHWPREDICT:
                    case CF_DEVSEASONAL:
                    case CF_SEASONAL:
                    case CF_DEVPREDICT:
                    case CF_FAILURES:
                        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].
                            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;
                    }
                    break;
                case 2:
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_HWPREDICT:
                    case CF_MHWPREDICT:
                        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);
                        if (atoi(token) < 1)
                            rrd_set_error("Invalid step: must be >= 1");
                        break;
                    }
                    break;
                case 3:
                    switch (cf_conv
                            (rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam)) {
                    case CF_HWPREDICT:
                    case CF_MHWPREDICT:
                        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:
                        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;
                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_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. */
                        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 */
                    free(argvcopy);
                    rrd_free2(&rrd);
                    return (-1);
                }
                token = strtok_r(NULL, ":", &tokptr);
                token_idx++;
            }           /* end while */
            free(argvcopy);
            if (token_idx < token_min){
                rrd_set_error("Expected at least %i arguments for RRA but got %i",token_min,token_idx);
                rrd_free2(&rrd);
                return(-1);
            }
#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
                 || cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) ==
                 CF_MHWPREDICT)
                && 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_set_error("creating contingent RRA");
                    rrd_free2(&rrd);
                    return -1;
                }
            }
            rrd.stat_head->rra_cnt++;
        } else {
            rrd_set_error("can't parse argument '%s'", argv[i]);
            rrd_free2(&rrd);
            return -1;
        }
    }


    if (rrd.stat_head->rra_cnt < 1) {
        rrd_set_error("you must define at least one Round Robin Archive");
        rrd_free2(&rrd);
        return (-1);
    }

    if (rrd.stat_head->ds_cnt < 1) {
        rrd_set_error("you must define at least one Data Source");
        rrd_free2(&rrd);
        return (-1);
    }
    return rrd_create_fn(filename, &rrd);
}
示例#3
0
rrd_info_t *rrd_info_r(
    char *filename)
{
    unsigned int i, ii = 0;
    rrd_t     rrd;
    rrd_info_t *data = NULL, *cd;
    rrd_infoval_t info;
    rrd_file_t *rrd_file;
    enum cf_en current_cf;
    enum dst_en current_ds;

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file == NULL)
        goto err_free;

    info.u_str = filename;
    cd = rrd_info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
    data = cd;

    info.u_str = rrd.stat_head->version;
    cd = rrd_info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info);

    info.u_cnt = rrd.stat_head->pdp_step;
    cd = rrd_info_push(cd, sprintf_alloc("step"), RD_I_CNT, info);

    info.u_cnt = rrd.live_head->last_up;
    cd = rrd_info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info);

    info.u_cnt = rrd_get_header_size(&rrd);
    cd = rrd_info_push(cd, sprintf_alloc("header_size"), RD_I_CNT, info);

    for (i = 0; i < rrd.stat_head->ds_cnt; i++) {

        info.u_cnt=i;
        cd= rrd_info_push(cd,sprintf_alloc("ds[%s].index",
                                     rrd.ds_def[i].ds_nam),
                     RD_I_CNT, info);
    
        info.u_str = rrd.ds_def[i].dst;
        cd = rrd_info_push(cd, sprintf_alloc("ds[%s].type",
                                             rrd.ds_def[i].ds_nam),
                           RD_I_STR, info);

        current_ds = dst_conv(rrd.ds_def[i].dst);
        switch (current_ds) {
        case DST_CDEF:
        {
            char     *buffer = NULL;

            rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
                            rrd.ds_def, &buffer);
            info.u_str = buffer;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].cdef",
                                             rrd.ds_def[i].ds_nam), RD_I_STR,
                               info);
            free(buffer);
        }
            break;
        default:
            info.u_cnt = rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].minimal_heartbeat",
                                             rrd.ds_def[i].ds_nam), RD_I_CNT,
                               info);

            info.u_val = rrd.ds_def[i].par[DS_min_val].u_val;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].min",
                                             rrd.ds_def[i].ds_nam), RD_I_VAL,
                               info);

            info.u_val = rrd.ds_def[i].par[DS_max_val].u_val;
            cd = rrd_info_push(cd,
                               sprintf_alloc("ds[%s].max",
                                             rrd.ds_def[i].ds_nam), RD_I_VAL,
                               info);
            break;
        }

        info.u_str = rrd.pdp_prep[i].last_ds;
        cd = rrd_info_push(cd,
                           sprintf_alloc("ds[%s].last_ds",
                                         rrd.ds_def[i].ds_nam), RD_I_STR,
                           info);

        info.u_val = rrd.pdp_prep[i].scratch[PDP_val].u_val;
        cd = rrd_info_push(cd,
                           sprintf_alloc("ds[%s].value",
                                         rrd.ds_def[i].ds_nam), RD_I_VAL,
                           info);

        info.u_cnt = rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt;
        cd = rrd_info_push(cd,
                           sprintf_alloc("ds[%s].unknown_sec",
                                         rrd.ds_def[i].ds_nam), RD_I_CNT,
                           info);
    }

    for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
        info.u_str = rrd.rra_def[i].cf_nam;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR,
                           info);
        current_cf = cf_conv(rrd.rra_def[i].cf_nam);

        info.u_cnt = rrd.rra_def[i].row_cnt;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT,
                           info);

        info.u_cnt = rrd.rra_ptr[i].cur_row;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cur_row", i), RD_I_CNT,
                           info);

        info.u_cnt = rrd.rra_def[i].pdp_cnt;
        cd = rrd_info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i),
                           RD_I_CNT, info);

        switch (current_cf) {
        case CF_HWPREDICT:
        case CF_MHWPREDICT:
            info.u_val = rrd.rra_def[i].par[RRA_hw_alpha].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].alpha", i),
                               RD_I_VAL, info);
            info.u_val = rrd.rra_def[i].par[RRA_hw_beta].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
                               info);
            break;
        case CF_SEASONAL:
        case CF_DEVSEASONAL:
            info.u_val = rrd.rra_def[i].par[RRA_seasonal_gamma].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].gamma", i),
                               RD_I_VAL, info);
            if (atoi(rrd.stat_head->version) >= 4) {
                info.u_val =
                    rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc("rra[%d].smoothing_window",
                                                 i), RD_I_VAL, info);
            }
            break;
        case CF_FAILURES:
            info.u_val = rrd.rra_def[i].par[RRA_delta_pos].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_pos", i),
                               RD_I_VAL, info);
            info.u_val = rrd.rra_def[i].par[RRA_delta_neg].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_neg", i),
                               RD_I_VAL, info);
            info.u_cnt = rrd.rra_def[i].par[RRA_failure_threshold].u_cnt;
            cd = rrd_info_push(cd,
                               sprintf_alloc("rra[%d].failure_threshold", i),
                               RD_I_CNT, info);
            info.u_cnt = rrd.rra_def[i].par[RRA_window_len].u_cnt;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].window_length", i),
                               RD_I_CNT, info);
            break;
        case CF_DEVPREDICT:
            break;
        default:
            info.u_val = rrd.rra_def[i].par[RRA_cdp_xff_val].u_val;
            cd = rrd_info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
                               info);
            break;
        }

        for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++) {
            switch (current_cf) {
            case CF_HWPREDICT:
            case CF_MHWPREDICT:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_hw_intercept].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].intercept", i, ii),
                                   RD_I_VAL, info);
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_hw_slope].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc("rra[%d].cdp_prep[%d].slope",
                                                 i, ii), RD_I_VAL, info);
                info.u_cnt =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_null_count].u_cnt;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].NaN_count", i, ii),
                                   RD_I_CNT, info);
                break;
            case CF_SEASONAL:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_hw_seasonal].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].seasonal", i, ii),
                                   RD_I_VAL, info);
                break;
            case CF_DEVSEASONAL:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_seasonal_deviation].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].deviation", i, ii),
                                   RD_I_VAL, info);
                break;
            case CF_DEVPREDICT:
                break;
            case CF_FAILURES:
            {
                unsigned short j;
                char     *violations_array;
                char      history[MAX_FAILURES_WINDOW_LEN + 1];

                violations_array =
                    (char *) rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                          ii].scratch;
                for (j = 0; j < rrd.rra_def[i].par[RRA_window_len].u_cnt; ++j)
                    history[j] = (violations_array[j] == 1) ? '1' : '0';
                history[j] = '\0';
                info.u_str = history;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].history", i, ii),
                                   RD_I_STR, info);
            }
                break;
            default:
                info.u_val =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_val].u_val;
                cd = rrd_info_push(cd,
                                   sprintf_alloc("rra[%d].cdp_prep[%d].value",
                                                 i, ii), RD_I_VAL, info);
                info.u_cnt =
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                 ii].scratch[CDP_unkn_pdp_cnt].u_cnt;
                cd = rrd_info_push(cd,
                                   sprintf_alloc
                                   ("rra[%d].cdp_prep[%d].unknown_datapoints",
                                    i, ii), RD_I_CNT, info);
                break;
            }
        }
    }

    rrd_close(rrd_file);
  err_free:
    rrd_free(&rrd);
    return (data);
}
示例#4
0
文件: rrd_fetch.c 项目: OPSF/uClinux
int
rrd_fetch(int argc, 
	  char **argv,
	  time_t         *start,
	  time_t         *end,       /* which time frame do you want ?
				      * will be changed to represent reality */
	  unsigned long  *step,      /* which stepsize do you want? 
				      * will be changed to represent reality */
	  unsigned long  *ds_cnt,    /* number of data sources in file */
	  char           ***ds_namv,   /* names of data sources */
	  rrd_value_t    **data)     /* two dimensional array containing the data */
{


    long     step_tmp =1;
    time_t   start_tmp=0, end_tmp=0;
    enum     cf_en cf_idx;

    struct rrd_time_value start_tv, end_tv;
    char     *parsetime_error = NULL;
    optind = 0; opterr = 0;  /* initialize getopt */

    /* init start and end time */
    parsetime("end-24h", &start_tv);
    parsetime("now", &end_tv);

    while (1){
	static struct option long_options[] =
	{
	    {"resolution",      required_argument, 0, 'r'},
	    {"start",      required_argument, 0, 's'},
	    {"end",      required_argument, 0, 'e'},
	    {0,0,0,0}
	};
	int option_index = 0;
	int opt;
	opt = getopt_long(argc, argv, "r:s:e:", 
			  long_options, &option_index);

	if (opt == EOF)
	    break;

	switch(opt) {
	case 's':
            if ((parsetime_error = parsetime(optarg, &start_tv))) {
                rrd_set_error( "start time: %s", parsetime_error );
                return -1;
	    }
	    break;
	case 'e':
            if ((parsetime_error = parsetime(optarg, &end_tv))) {
                rrd_set_error( "end time: %s", parsetime_error );
                return -1;
	    }
	    break;
	case 'r':
	    step_tmp = atol(optarg);
	    break;
	case '?':
	    rrd_set_error("unknown option '-%c'",optopt);
	    return(-1);
	}
    }

    
    if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
	return -1;
    }  

    
    if (start_tmp < 3600*24*365*10){
	rrd_set_error("the first entry to fetch should be after 1980");
	return(-1);
    }
    
    if (end_tmp < start_tmp) {
	rrd_set_error("start (%ld) should be less than end (%ld)", start_tmp, end_tmp);
	return(-1);
    }
    
    *start = start_tmp;
    *end = end_tmp;

    if (step_tmp < 1) {
	rrd_set_error("step must be >= 1 second");
	return -1;
    }
    *step = step_tmp;
    
    if (optind + 1 >= argc){
	rrd_set_error("not enough arguments");
	return -1;
    }
    
    if ((int)(cf_idx=cf_conv(argv[optind+1])) == -1 ){
	return -1;
    }

    if (rrd_fetch_fn(argv[optind],cf_idx,start,end,step,ds_cnt,ds_namv,data) == -1)
	return(-1);
    return (0);
}
示例#5
0
文件: rrd_fetch.c 项目: OPSF/uClinux
int
rrd_fetch_fn(
    char           *filename,  /* name of the rrd */
    enum cf_en     cf_idx,         /* which consolidation function ?*/
    time_t         *start,
    time_t         *end,       /* which time frame do you want ?
			        * will be changed to represent reality */
    unsigned long  *step,      /* which stepsize do you want? 
				* will be changed to represent reality */
    unsigned long  *ds_cnt,    /* number of data sources in file */
    char           ***ds_namv,   /* names of data_sources */
    rrd_value_t    **data)     /* two dimensional array containing the data */
{
    long           i,ii;
    FILE           *in_file;
    time_t         cal_start,cal_end, rra_start_time,rra_end_time;
    long  best_full_rra=0, best_part_rra=0, chosen_rra=0, rra_pointer=0;
    long  best_step_diff=0, tmp_step_diff=0, tmp_match=0, best_match=0;
    long  full_match, rra_base;
    long           start_offset, end_offset;
    int            first_full = 1;
    int            first_part = 1;
    rrd_t     rrd;
    rrd_value_t    *data_ptr;
    unsigned long  rows = (*end - *start) / *step;

#ifdef DEBUG
fprintf(stderr,"Entered rrd_fetch_fn() searching for the best match\n");
fprintf(stderr,"Looking for: start %10lu end %10lu step %5lu rows  %lu\n",
						*start,*end,*step,rows);
#endif

    if(rrd_open(filename,&in_file,&rrd, RRD_READONLY)==-1)
	return(-1);
    
    /* when was the really last update of this file ? */

    if (((*ds_namv) = (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char*)))==NULL){
	rrd_set_error("malloc fetch ds_namv array");
	rrd_free(&rrd);
	fclose(in_file);
	return(-1);
    }
    
    for(i=0;(unsigned long)i<rrd.stat_head->ds_cnt;i++){
	if ((((*ds_namv)[i]) = malloc(sizeof(char) * DS_NAM_SIZE))==NULL){
	    rrd_set_error("malloc fetch ds_namv entry");
	    rrd_free(&rrd);
	    free(*ds_namv);
	    fclose(in_file);
	    return(-1);
	}
	strncpy((*ds_namv)[i],rrd.ds_def[i].ds_nam,DS_NAM_SIZE-1);
	(*ds_namv)[i][DS_NAM_SIZE-1]='\0';

    }
    
    /* find the rra which best matches the requirements */
    for(i=0;(unsigned)i<rrd.stat_head->rra_cnt;i++){
	if(cf_conv(rrd.rra_def[i].cf_nam) == cf_idx){
	    
	    cal_end = (rrd.live_head->last_up - (rrd.live_head->last_up 
			  % (rrd.rra_def[i].pdp_cnt 
			     * rrd.stat_head->pdp_step)));
	    cal_start = (cal_end 
			 - (rrd.rra_def[i].pdp_cnt 
			    * rrd.rra_def[i].row_cnt
			    * rrd.stat_head->pdp_step));

	    full_match = *end -*start;
#ifdef DEBUG
fprintf(stderr,"Considering: start %10lu end %10lu step %5lu ",
							cal_start,cal_end,
			rrd.stat_head->pdp_step * rrd.rra_def[i].pdp_cnt);
#endif
 	    /* we need step difference in either full or partial case */
 	    tmp_step_diff = labs(*step - (rrd.stat_head->pdp_step
					   * rrd.rra_def[i].pdp_cnt));
	    /* best full match */
	    if(cal_end >= *end 
	       && cal_start <= *start){
		if (first_full || (tmp_step_diff < best_step_diff)){
		    first_full=0;
		    best_step_diff = tmp_step_diff;
		    best_full_rra=i;
#ifdef DEBUG
fprintf(stderr,"best full match so far\n");
#endif
		} else {
#ifdef DEBUG
fprintf(stderr,"full match, not best\n");
#endif
		}
		
	    } else {
		/* best partial match */
		tmp_match = full_match;
		if (cal_start>*start)
		    tmp_match -= (cal_start-*start);
		if (cal_end<*end)
		    tmp_match -= (*end-cal_end);		
		if (first_part ||
                    (best_match < tmp_match) ||
                    (best_match == tmp_match && 
                     tmp_step_diff < best_step_diff)){ 
#ifdef DEBUG
fprintf(stderr,"best partial so far\n");
#endif
		    first_part=0;
		    best_match = tmp_match;
		    best_step_diff = tmp_step_diff;
		    best_part_rra =i;
		} else {
#ifdef DEBUG
fprintf(stderr,"partial match, not best\n");
#endif
		}
	    }
	}
    }

    /* lets see how the matching went. */
    if (first_full==0)
	chosen_rra = best_full_rra;
    else if (first_part==0)
	chosen_rra = best_part_rra;
    else {
	rrd_set_error("the RRD does not contain an RRA matching the chosen CF");
	rrd_free(&rrd);
	fclose(in_file);
	return(-1);
    }
	
    /* set the wish parameters to their real values */
    *step = rrd.stat_head->pdp_step * rrd.rra_def[chosen_rra].pdp_cnt;
    *start -= (*start % *step);
    if (*end % *step) *end += (*step - *end % *step);
    rows = (*end - *start) / *step;

#ifdef DEBUG
    fprintf(stderr,"We found:    start %10lu end %10lu step %5lu rows  %lu\n",
						*start,*end,*step,rows);
#endif

/* Start and end are now multiples of the step size.  The amount of
** steps we want is (end-start)/step and *not* an extra one.
** Reasoning:  if step is s and we want to graph from t to t+s,
** we need exactly ((t+s)-t)/s rows.  The row to collect from the
** database is the one with time stamp (t+s) which means t to t+s.
*/
    *ds_cnt =   rrd.stat_head->ds_cnt; 
    if (((*data) = malloc(*ds_cnt * rows * sizeof(rrd_value_t)))==NULL){
	rrd_set_error("malloc fetch data area");
	for (i=0;(unsigned long)i<*ds_cnt;i++)
	      free((*ds_namv)[i]);
	free(*ds_namv);
	rrd_free(&rrd);
	fclose(in_file);
	return(-1);
    }
    
    data_ptr=(*data);
    
    /* find base address of rra */
    rra_base=ftell(in_file);
    for(i=0;i<chosen_rra;i++)
	rra_base += ( *ds_cnt
		      * rrd.rra_def[i].row_cnt
		      * sizeof(rrd_value_t));

    /* find start and end offset */
    rra_end_time = (rrd.live_head->last_up 
		    - (rrd.live_head->last_up % *step));
    rra_start_time = (rra_end_time
		 - ( *step * (rrd.rra_def[chosen_rra].row_cnt-1)));
    /* here's an error by one if we don't be careful */
    start_offset =(long)(*start + *step - rra_start_time) / (long)*step;
    end_offset = (long)(rra_end_time - *end ) / (long)*step; 
#ifdef DEBUG
    fprintf(stderr,"rra_start %lu, rra_end %lu, start_off %li, end_off %li\n",
	    rra_start_time,rra_end_time,start_offset,end_offset);
#endif

    /* fill the gap at the start if needs be */

    if (start_offset <= 0)
	rra_pointer = rrd.rra_ptr[chosen_rra].cur_row+1;
    else 
	rra_pointer = rrd.rra_ptr[chosen_rra].cur_row+1+start_offset;
    
    if(fseek(in_file,(rra_base 
		   + (rra_pointer
		      * *ds_cnt
		      * sizeof(rrd_value_t))),SEEK_SET) != 0){
	rrd_set_error("seek error in RRA");
	for (i=0;(unsigned)i<*ds_cnt;i++)
	      free((*ds_namv)[i]);
	free(*ds_namv);
	rrd_free(&rrd);
	free(*data);
	*data = NULL;
	fclose(in_file);
	return(-1);

    }
#ifdef DEBUG
    fprintf(stderr,"First Seek: rra_base %lu rra_pointer %lu\n",
	    rra_base, rra_pointer);
#endif
    /* step trough the array */

    for (i=start_offset;
	 i< (signed)rrd.rra_def[chosen_rra].row_cnt - end_offset;
	 i++){
	/* no valid data yet */
	if (i<0) {
#ifdef DEBUG
	    fprintf(stderr,"pre fetch %li -- ",i);
#endif
	    for(ii=0;(unsigned)ii<*ds_cnt;ii++){
		*(data_ptr++) = DNAN;
#ifdef DEBUG
		fprintf(stderr,"%10.2f ",*(data_ptr-1));
#endif
	    }
	} 
	/* past the valid data area */
	else if (i >= (signed)rrd.rra_def[chosen_rra].row_cnt) {
#ifdef DEBUG
	    fprintf(stderr,"post fetch %li -- ",i);
#endif
	    for(ii=0;(unsigned)ii<*ds_cnt;ii++){
		*(data_ptr++) = DNAN;
#ifdef DEBUG
		fprintf(stderr,"%10.2f ",*(data_ptr-1));
#endif
	    }
	} else {
	    /* OK we are inside the valid area but the pointer has to 
	     * be wrapped*/
	    if (rra_pointer >= (signed)rrd.rra_def[chosen_rra].row_cnt) {
		rra_pointer -= rrd.rra_def[chosen_rra].row_cnt;
		if(fseek(in_file,(rra_base+rra_pointer
			       * *ds_cnt
			       * sizeof(rrd_value_t)),SEEK_SET) != 0){
		    rrd_set_error("wrap seek in RRA did fail");
		    for (ii=0;(unsigned)ii<*ds_cnt;ii++)
			free((*ds_namv)[ii]);
		    free(*ds_namv);
		    rrd_free(&rrd);
		    free(*data);
		    *data = NULL;
		    fclose(in_file);
		    return(-1);
		}
#ifdef DEBUG
		fprintf(stderr,"wrap seek ...\n");
#endif	    
	    }
	    
	    if(fread(data_ptr,
		     sizeof(rrd_value_t),
		     *ds_cnt,in_file) != rrd.stat_head->ds_cnt){
		rrd_set_error("fetching cdp from rra");
		for (ii=0;(unsigned)ii<*ds_cnt;ii++)
		    free((*ds_namv)[ii]);
		free(*ds_namv);
		rrd_free(&rrd);
		free(*data);
		*data = NULL;
		fclose(in_file);
		return(-1);
	    }
#ifdef DEBUG
	    fprintf(stderr,"post fetch %li -- ",i);
	    for(ii=0;ii<*ds_cnt;ii++)
		fprintf(stderr,"%10.2f ",*(data_ptr+ii));
#endif
	    data_ptr += *ds_cnt;
	    rra_pointer ++;
	}
#ifdef DEBUG
	    fprintf(stderr,"\n");
#endif	    
	
    }
    rrd_free(&rrd);
    fclose(in_file);
    return(0);
}
示例#6
0
int rrd_fetch_fn(
    const char *filename,   /* name of the rrd */
    enum cf_en cf_idx,  /* which consolidation function ? */
    time_t *start,
    time_t *end,        /* which time frame do you want ?
                         * will be changed to represent reality */
    unsigned long *step,    /* which stepsize do you want?
                             * will be changed to represent reality */
    unsigned long *ds_cnt,  /* number of data sources in file */
    char ***ds_namv,    /* names of data_sources */
    rrd_value_t **data)
{   /* two dimensional array containing the data */
    long      i, ii;
    time_t    cal_start, cal_end, rra_start_time, rra_end_time;
    long      best_full_rra = 0, best_part_rra = 0, chosen_rra =
                                  0, rra_pointer = 0;
    long      best_full_step_diff = 0, best_part_step_diff =
                                        0, tmp_step_diff = 0, tmp_match = 0, best_match = 0;
    long      full_match, rra_base;
    off_t     start_offset, end_offset;
    int       first_full = 1;
    int       first_part = 1;
    rrd_t     rrd;
    rrd_file_t *rrd_file;
    rrd_value_t *data_ptr;
    unsigned long rows;

#ifdef DEBUG
    fprintf(stderr, "Entered rrd_fetch_fn() searching for the best match\n");
    fprintf(stderr, "Looking for: start %10lu end %10lu step %5lu\n",
            *start, *end, *step);
#endif

#ifdef HAVE_LIBDBI
    /* handle libdbi datasources */
    if (strncmp("sql//",filename,5)==0) {
        return rrd_fetch_fn_libdbi(filename,cf_idx,start,end,step,ds_cnt,ds_namv,data);
    }
#endif

    rrd_init(&rrd);
    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
    if (rrd_file == NULL)
        goto err_free;

    /* when was the really last update of this file ? */

    if (((*ds_namv) =
                (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) {
        rrd_set_error("malloc fetch ds_namv array");
        goto err_close;
    }

    for (i = 0; (unsigned long) i < rrd.stat_head->ds_cnt; i++) {
        if ((((*ds_namv)[i]) = (char*)malloc(sizeof(char) * DS_NAM_SIZE)) == NULL) {
            rrd_set_error("malloc fetch ds_namv entry");
            goto err_free_ds_namv;
        }
        strncpy((*ds_namv)[i], rrd.ds_def[i].ds_nam, DS_NAM_SIZE - 1);
        (*ds_namv)[i][DS_NAM_SIZE - 1] = '\0';

    }

    /* find the rra which best matches the requirements */
    for (i = 0; (unsigned) i < rrd.stat_head->rra_cnt; i++) {
        enum cf_en rratype=cf_conv(rrd.rra_def[i].cf_nam);
        /* handle this RRA */
        if (
            /* if we found a direct match */
            (rratype == cf_idx)
            ||
            /*if we found a DS with interval 1
              and CF (requested,available) are MIN,MAX,AVERAGE,LAST
            */
            (
                /* only if we are on interval 1 */
                (rrd.rra_def[i].pdp_cnt==1)
                && (
                    /* and requested CF is MIN,MAX,AVERAGE,LAST */
                    (cf_idx == CF_MINIMUM)
                    ||(cf_idx == CF_MAXIMUM)
                    ||(cf_idx == CF_AVERAGE)
                    ||(cf_idx == CF_LAST)
                )
                && (
                    /* and found CF is MIN,MAX,AVERAGE,LAST */
                    (rratype == CF_MINIMUM)
                    ||(rratype == CF_MAXIMUM)
                    ||(rratype == CF_AVERAGE)
                    ||(rratype == CF_LAST)
                )
            )
        ) {

            cal_end = (rrd.live_head->last_up - (rrd.live_head->last_up
                                                 % (rrd.rra_def[i].pdp_cnt
                                                    *
                                                    rrd.stat_head->
                                                    pdp_step)));
            cal_start =
                (cal_end -
                 (rrd.rra_def[i].pdp_cnt * rrd.rra_def[i].row_cnt *
                  rrd.stat_head->pdp_step));

            full_match = *end - *start;
#ifdef DEBUG
            fprintf(stderr, "Considering: start %10lu end %10lu step %5lu ",
                    cal_start, cal_end,
                    rrd.stat_head->pdp_step * rrd.rra_def[i].pdp_cnt);
#endif
            /* we need step difference in either full or partial case */
            tmp_step_diff = labs(*step - (rrd.stat_head->pdp_step
                                          * rrd.rra_def[i].pdp_cnt));
            /* best full match */
            if (cal_start <= *start) {
                if (first_full || (tmp_step_diff < best_full_step_diff)) {
                    first_full = 0;
                    best_full_step_diff = tmp_step_diff;
                    best_full_rra = i;
#ifdef DEBUG
                    fprintf(stderr, "best full match so far\n");
                } else {
                    fprintf(stderr, "full match, not best\n");
#endif
                }

            } else {
                /* best partial match */
                tmp_match = full_match;
                if (cal_start > *start)
                    tmp_match -= (cal_start - *start);
                if (first_part ||
                        (best_match < tmp_match) ||
                        (best_match == tmp_match &&
                         tmp_step_diff < best_part_step_diff)) {
#ifdef DEBUG
                    fprintf(stderr, "best partial so far\n");
#endif
                    first_part = 0;
                    best_match = tmp_match;
                    best_part_step_diff = tmp_step_diff;
                    best_part_rra = i;
                } else {
#ifdef DEBUG
                    fprintf(stderr, "partial match, not best\n");
#endif
                }
            }
        }
    }

    /* lets see how the matching went. */
    if (first_full == 0)
        chosen_rra = best_full_rra;
    else if (first_part == 0)
        chosen_rra = best_part_rra;
    else {
        rrd_set_error
        ("the RRD does not contain an RRA matching the chosen CF");
        goto err_free_all_ds_namv;
    }

    /* set the wish parameters to their real values */
    *step = rrd.stat_head->pdp_step * rrd.rra_def[chosen_rra].pdp_cnt;
    *start -= (*start % *step);
    *end += (*step - *end % *step);
    rows = (*end - *start) / *step + 1;

#ifdef DEBUG
    fprintf(stderr,
            "We found:    start %10lu end %10lu step %5lu rows  %lu\n",
            *start, *end, *step, rows);
#endif

    /* Start and end are now multiples of the step size.  The amount of
    ** steps we want is (end-start)/step and *not* an extra one.
    ** Reasoning:  if step is s and we want to graph from t to t+s,
    ** we need exactly ((t+s)-t)/s rows.  The row to collect from the
    ** database is the one with time stamp (t+s) which means t to t+s.
    */
    *ds_cnt = rrd.stat_head->ds_cnt;
    if (((*data) = (rrd_value_t*)malloc(*ds_cnt * rows * sizeof(rrd_value_t))) == NULL) {
        rrd_set_error("malloc fetch data area");
        goto err_free_all_ds_namv;
    }

    data_ptr = (*data);

    /* find base address of rra */
    rra_base = rrd_file->header_len;
    for (i = 0; i < chosen_rra; i++)
        rra_base += (*ds_cnt * rrd.rra_def[i].row_cnt * sizeof(rrd_value_t));

    /* find start and end offset */
    rra_end_time = (rrd.live_head->last_up
                    - (rrd.live_head->last_up % *step));
    rra_start_time = (rra_end_time
                      - (*step * (rrd.rra_def[chosen_rra].row_cnt - 1)));
    /* here's an error by one if we don't be careful */
    start_offset = ((long long)*start + (long long)*step - (long long)rra_start_time) / (long long) *step;
    end_offset = ((long long)rra_end_time - (long long)*end) / (long long) *step;
#ifdef DEBUG
    fprintf(stderr,
            "start %10lu step %10lu rra_start %lld, rra_end %lld, start_off %lld, end_off %lld\n",
            *start, *step,(long long)rra_start_time, (long long)rra_end_time, (long long)start_offset, (long long)end_offset);
#endif
    /* only seek if the start time is before the end time */
    if (*start <= rra_end_time && *end >= rra_start_time - (off_t)*step ) {
        if (start_offset <= 0)
            rra_pointer = rrd.rra_ptr[chosen_rra].cur_row + 1;
        else
            rra_pointer = rrd.rra_ptr[chosen_rra].cur_row + 1 + start_offset;

        rra_pointer = rra_pointer % (signed) rrd.rra_def[chosen_rra].row_cnt;

        if (rrd_seek(rrd_file, (rra_base + (rra_pointer * (*ds_cnt)
                                            * sizeof(rrd_value_t))),
                     SEEK_SET) != 0) {
            rrd_set_error("seek error in RRA");
            goto err_free_data;
        }
#ifdef DEBUG
        fprintf(stderr, "First Seek: rra_base %lu rra_pointer %lu\n",
                rra_base, rra_pointer);
#endif
    }

    /* step trough the array */

    for (i = start_offset;
            i < (signed) rrd.rra_def[chosen_rra].row_cnt - end_offset; i++) {
        /* no valid data yet */
        if (i < 0) {
#ifdef DEBUG
            fprintf(stderr, "pre fetch %li -- ", i);
#endif
            for (ii = 0; (unsigned) ii < *ds_cnt; ii++) {
                *(data_ptr++) = DNAN;
#ifdef DEBUG
                fprintf(stderr, "%10.2f ", *(data_ptr - 1));
#endif
            }
        }
        /* past the valid data area */
        else if (i >= (signed) rrd.rra_def[chosen_rra].row_cnt) {
#ifdef DEBUG
            fprintf(stderr, "past fetch %li -- ", i);
#endif
            for (ii = 0; (unsigned) ii < *ds_cnt; ii++) {
                *(data_ptr++) = DNAN;
#ifdef DEBUG
                fprintf(stderr, "%10.2f ", *(data_ptr - 1));
#endif
            }
        } else {
            /* OK we are inside the valid area but the pointer has to
             * be wrapped*/
            if (rra_pointer >= (signed) rrd.rra_def[chosen_rra].row_cnt) {
                rra_pointer -= rrd.rra_def[chosen_rra].row_cnt;
                if (rrd_seek(rrd_file, (rra_base + rra_pointer * (*ds_cnt)
                                        * sizeof(rrd_value_t)),
                             SEEK_SET) != 0) {
                    rrd_set_error("wrap seek in RRA did fail");
                    goto err_free_data;
                }
#ifdef DEBUG
                fprintf(stderr, "wrap seek ...\n");
#endif
            }

            if (rrd_read(rrd_file, data_ptr, sizeof(rrd_value_t) * (*ds_cnt))
                    != (ssize_t) (sizeof(rrd_value_t) * (*ds_cnt))) {
                rrd_set_error("fetching cdp from rra");
                goto err_free_data;
            }
#ifdef DEBUG
            fprintf(stderr, "post fetch %li -- ", i);
            for (ii = 0; ii < *ds_cnt; ii++)
                fprintf(stderr, "%10.2f ", *(data_ptr + ii));
#endif
            data_ptr += *ds_cnt;
            rra_pointer++;
        }
#ifdef DEBUG
        fprintf(stderr, "\n");
#endif

    }

    rrd_close(rrd_file);
    rrd_free(&rrd);
    return (0);
err_free_data:
    free(*data);
    *data = NULL;
err_free_all_ds_namv:
    for (i = 0; (unsigned long) i < rrd.stat_head->ds_cnt; ++i)
        free((*ds_namv)[i]);
err_free_ds_namv:
    free(*ds_namv);
err_close:
    rrd_close(rrd_file);
err_free:
    rrd_free(&rrd);
    return (-1);
}
示例#7
0
int rrd_dump_cb_r(
    const char *filename,
    int opt_header,
    rrd_output_callback_t cb,
    void *user)
{
    unsigned int i, ii, ix, iii = 0;
    time_t    now;
    char      somestring[255];
    rrd_value_t my_cdp;
    off_t     rra_base, rra_start, rra_next;
    rrd_file_t *rrd_file;
    rrd_t     rrd;
    rrd_value_t value;
    struct tm tm;
    char *old_locale = "";

//These two macros are local defines to clean up visible code from its redndancy
//and make it easier to read.
#define CB_PUTS(str)                                            \
    cb((str), strlen((str)), user)
#define CB_FMTS(...) do {                                       \
    char buffer[256];                                           \
    snprintf (buffer, sizeof(buffer), __VA_ARGS__);             \
    CB_PUTS (buffer);                                           \
    } while (0)
//These macros are to be undefined at the end of this function

    //Check if we got a (valid) callback method
    if (!cb) {
        return (-1);
    }

    rrd_init(&rrd);

    rrd_file = rrd_open(filename, &rrd, RRD_READONLY | RRD_READAHEAD);
    if (rrd_file == NULL) {
        rrd_free(&rrd);
        return (-1);
    }

    old_locale = setlocale(LC_NUMERIC, NULL);
    setlocale(LC_NUMERIC, "C");


    if (opt_header == 1) {
        CB_PUTS("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        CB_PUTS("<!DOCTYPE rrd SYSTEM \"http://oss.oetiker.ch/rrdtool/rrdtool.dtd\">\n");
        CB_PUTS("<!-- Round Robin Database Dump -->\n");
        CB_PUTS("<rrd>\n");
    } else if (opt_header == 2) {
        CB_PUTS("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        CB_PUTS("<!-- Round Robin Database Dump -->\n");
        CB_PUTS("<rrd xmlns=\"http://oss.oetiker.ch/rrdtool/rrdtool-dump.xml\" "
                "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
        CB_PUTS("\txsi:schemaLocation=\"http://oss.oetiker.ch/rrdtool/rrdtool-dump.xml "
                "http://oss.oetiker.ch/rrdtool/rrdtool-dump.xsd\">\n");
    } else {
        CB_PUTS("<!-- Round Robin Database Dump -->\n");
        CB_PUTS("<rrd>\n");
    }

    if (atoi(rrd.stat_head->version) <= 3) {
        CB_FMTS("\t<version>%s</version>\n", RRD_VERSION3);
    } else {
        CB_FMTS("\t<version>%s</version>\n", RRD_VERSION);
    }
    
    CB_FMTS("\t<step>%lu</step> <!-- Seconds -->\n",
        rrd.stat_head->pdp_step);

#ifdef HAVE_STRFTIME
    localtime_r(&rrd.live_head->last_up, &tm);
    strftime(somestring, 255, "%Y-%m-%d %H:%M:%S %Z", &tm);
#else
# error "Need strftime"
#endif
    CB_FMTS("\t<lastupdate>%lld</lastupdate> <!-- %s -->\n\n",
        (long long int) rrd.live_head->last_up, somestring);
    for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
        CB_PUTS("\t<ds>\n");

        CB_FMTS("\t\t<name> %s </name>\n", rrd.ds_def[i].ds_nam);

        CB_FMTS("\t\t<type> %s </type>\n", rrd.ds_def[i].dst);

        if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) {
            CB_FMTS("\t\t<minimal_heartbeat>%lu</minimal_heartbeat>\n",
                    rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);

            if (isnan(rrd.ds_def[i].par[DS_min_val].u_val)) {
                CB_PUTS("\t\t<min>NaN</min>\n");
            } else {
                CB_FMTS("\t\t<min>%0.10e</min>\n",
                    rrd.ds_def[i].par[DS_min_val].u_val);
            }
            
            if (isnan(rrd.ds_def[i].par[DS_max_val].u_val)) {
                CB_PUTS("\t\t<max>NaN</max>\n");
            } else {
                CB_FMTS("\t\t<max>%0.10e</max>\n",
                    rrd.ds_def[i].par[DS_max_val].u_val);
            }
        } else {        /* DST_CDEF */
            char     *str = NULL;

            rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
                rrd.ds_def, &str);

            //Splitting into 3 writes to avoid allocating memory
            //This is better compared to snprintf as str may be of arbitrary size
            CB_PUTS("\t\t<cdef> ");
            CB_PUTS(str);
            CB_PUTS(" </cdef>\n");

            free(str);
        }

        CB_PUTS("\n\t\t<!-- PDP Status -->\n");
        CB_FMTS("\t\t<last_ds>%s</last_ds>\n",
            rrd.pdp_prep[i].last_ds);

        if (isnan(rrd.pdp_prep[i].scratch[PDP_val].u_val)) {
            CB_PUTS("\t\t<value>NaN</value>\n");
        } else {
            CB_FMTS("\t\t<value>%0.10e</value>\n",
                rrd.pdp_prep[i].scratch[PDP_val].u_val);
        }

        CB_FMTS("\t\t<unknown_sec> %lu </unknown_sec>\n",
            rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);

        CB_PUTS("\t</ds>\n\n");
    }

    CB_PUTS("\t<!-- Round Robin Archives -->\n");

    rra_base = rrd_file->header_len;
    rra_next = rra_base;

    for (i = 0; i < rrd.stat_head->rra_cnt; i++) {

        long      timer = 0;

        rra_start = rra_next;
        rra_next += (rrd.stat_head->ds_cnt
                     * rrd.rra_def[i].row_cnt * sizeof(rrd_value_t));

        CB_PUTS("\t<rra>\n");

        CB_FMTS("\t\t<cf>%s</cf>\n", rrd.rra_def[i].cf_nam);

        CB_FMTS("\t\t<pdp_per_row>%lu</pdp_per_row> <!-- %lu seconds -->\n\n",
            rrd.rra_def[i].pdp_cnt, 
            rrd.rra_def[i].pdp_cnt * rrd.stat_head->pdp_step);

        /* support for RRA parameters */
        CB_PUTS("\t\t<params>\n");

        switch (cf_conv(rrd.rra_def[i].cf_nam)) {
        case CF_HWPREDICT:
        case CF_MHWPREDICT:
            CB_FMTS("\t\t<hw_alpha>%0.10e</hw_alpha>\n",
                rrd.rra_def[i].par[RRA_hw_alpha].u_val);

            CB_FMTS("\t\t<hw_beta>%0.10e</hw_beta>\n",
                rrd.rra_def[i].par[RRA_hw_beta].u_val);

            CB_FMTS("\t\t<dependent_rra_idx>%lu</dependent_rra_idx>\n",
                rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
            break;
        case CF_SEASONAL:
        case CF_DEVSEASONAL:
            CB_FMTS("\t\t<seasonal_gamma>%0.10e</seasonal_gamma>\n",
                rrd.rra_def[i].par[RRA_seasonal_gamma].u_val);

            CB_FMTS("\t\t<seasonal_smooth_idx>%lu</seasonal_smooth_idx>\n",
                rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt);

            if (atoi(rrd.stat_head->version) >= 4) {
                CB_FMTS("\t\t<smoothing_window>%0.10e</smoothing_window>\n",
                    rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val);
            }

            CB_FMTS("\t\t<dependent_rra_idx>%lu</dependent_rra_idx>\n",
                rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
            break;
        case CF_FAILURES:
            CB_FMTS("\t\t<delta_pos>%0.10e</delta_pos>\n",
                rrd.rra_def[i].par[RRA_delta_pos].u_val);

            CB_FMTS("\t\t<delta_neg>%0.10e</delta_neg>\n",
                rrd.rra_def[i].par[RRA_delta_neg].u_val);

            CB_FMTS("\t\t<window_len>%lu</window_len>\n",
                rrd.rra_def[i].par[RRA_window_len].u_cnt);

            CB_FMTS("\t\t<failure_threshold>%lu</failure_threshold>\n",
                rrd.rra_def[i].par[RRA_failure_threshold].u_cnt);

            /* fall thru */
        case CF_DEVPREDICT:
            CB_FMTS("\t\t<dependent_rra_idx>%lu</dependent_rra_idx>\n",
                rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
            break;
        case CF_AVERAGE:
        case CF_MAXIMUM:
        case CF_MINIMUM:
        case CF_LAST:
        default:
            CB_FMTS("\t\t<xff>%0.10e</xff>\n",
                rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
            break;
        }

        CB_PUTS("\t\t</params>\n");
        CB_PUTS("\t\t<cdp_prep>\n");

        for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++) {
            unsigned long ivalue;

            CB_PUTS("\t\t\t<ds>\n");
            /* support for exporting all CDP parameters */
            /* parameters common to all CFs */
            /* primary_val and secondary_val do not need to be saved between updates
             * so strictly speaking they could be omitted.
             * However, they can be useful for diagnostic purposes, so are included here. */
            value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                scratch[CDP_primary_val].u_val;
            if (isnan(value)) {
                CB_PUTS("\t\t\t<primary_value>NaN</primary_value>\n");
            } else {
                CB_FMTS("\t\t\t<primary_value>%0.10e</primary_value>\n", value);
            }

            value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                scratch[CDP_secondary_val].u_val;
            if (isnan(value)) {
                CB_PUTS("\t\t\t<secondary_value>NaN</secondary_value>\n");
            } else {
                CB_FMTS("\t\t\t<secondary_value>%0.10e</secondary_value>\n", value);
            }

            switch (cf_conv(rrd.rra_def[i].cf_nam)) {
            case CF_HWPREDICT:
            case CF_MHWPREDICT:
                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_intercept].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<intercept>NaN</intercept>\n");
                } else {
                    CB_FMTS("\t\t\t<intercept>%0.10e</intercept>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_last_intercept].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<last_intercept>NaN</last_intercept>\n");
                } else {
                    CB_FMTS("\t\t\t<last_intercept>%0.10e</last_intercept>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_slope].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<slope>NaN</slope>\n");
                } else {
                    CB_FMTS("\t\t\t<slope>%0.10e</slope>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_last_slope].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<last_slope>NaN</last_slope>\n");
                } else {
                    CB_FMTS("\t\t\t<last_slope>%0.10e</last_slope>\n", value);
                }

                ivalue = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_null_count].u_cnt;
                CB_FMTS("\t\t\t<nan_count>%lu</nan_count>\n", ivalue);

                ivalue = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_last_null_count].u_cnt;
                CB_FMTS("\t\t\t<last_nan_count>%lu</last_nan_count>\n", ivalue);
                break;
            case CF_SEASONAL:
            case CF_DEVSEASONAL:
                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_seasonal].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<seasonal>NaN</seasonal>\n");
                } else {
                    CB_FMTS("\t\t\t<seasonal>%0.10e</seasonal>\n", value);
                }

                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_hw_last_seasonal].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<last_seasonal>NaN</last_seasonal>\n");
                } else {
                    CB_FMTS("\t\t\t<last_seasonal>%0.10e</last_seasonal>\n", value);
                }

                ivalue = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                    scratch[CDP_init_seasonal].u_cnt;
                CB_FMTS("\t\t\t<init_flag>%lu</init_flag>\n", ivalue);
                break;
            case CF_DEVPREDICT:
                break;
            case CF_FAILURES:
            {
                unsigned short vidx;
                char *violations_array = (char *) ((void *)
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].scratch);
                CB_PUTS("\t\t\t<history>");
                for (vidx = 0;
                    vidx < rrd.rra_def[i].par[RRA_window_len].u_cnt;
                    ++vidx) {
                    CB_FMTS("%d", violations_array[vidx]);
                }
                CB_PUTS("</history>\n");
            }
                break;
            case CF_AVERAGE:
            case CF_MAXIMUM:
            case CF_MINIMUM:
            case CF_LAST:
            default:
                value = rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].scratch[CDP_val].u_val;
                if (isnan(value)) {
                    CB_PUTS("\t\t\t<value>NaN</value>\n");
                } else {
                    CB_FMTS("\t\t\t<value>%0.10e</value>\n", value);
                }

                CB_FMTS("\t\t\t<unknown_datapoints>%lu</unknown_datapoints>\n",
                    rrd.cdp_prep[i * rrd.stat_head->ds_cnt + ii].
                        scratch[CDP_unkn_pdp_cnt].u_cnt);
                break;
            }
            CB_PUTS("\t\t\t</ds>\n");
        }
        CB_PUTS("\t\t</cdp_prep>\n");

        CB_PUTS("\t\t<database>\n");
        rrd_seek(rrd_file, (rra_start + (rrd.rra_ptr[i].cur_row + 1)
                            * rrd.stat_head->ds_cnt
                            * sizeof(rrd_value_t)), SEEK_SET);
        timer = -(long)(rrd.rra_def[i].row_cnt - 1);
        ii = rrd.rra_ptr[i].cur_row;
        for (ix = 0; ix < rrd.rra_def[i].row_cnt; ix++) {
            ii++;
            if (ii >= rrd.rra_def[i].row_cnt) {
                rrd_seek(rrd_file, rra_start, SEEK_SET);
                ii = 0; /* wrap if max row cnt is reached */
            }
            now = (rrd.live_head->last_up
                   - rrd.live_head->last_up
                   % (rrd.rra_def[i].pdp_cnt * rrd.stat_head->pdp_step))
                + (timer * rrd.rra_def[i].pdp_cnt * rrd.stat_head->pdp_step);

            timer++;
#if HAVE_STRFTIME
            localtime_r(&now, &tm);
            strftime(somestring, 255, "%Y-%m-%d %H:%M:%S %Z", &tm);
#else
# error "Need strftime"
#endif
            CB_FMTS("\t\t\t<!-- %s / %lld --> <row>",  somestring, (long long int) now);
            for (iii = 0; iii < rrd.stat_head->ds_cnt; iii++) {
                rrd_read(rrd_file, &my_cdp, sizeof(rrd_value_t) * 1);
                if (isnan(my_cdp)) {
                    CB_PUTS("<v>NaN</v>");
                } else {
                    CB_FMTS("<v>%0.10e</v>", my_cdp);
                }
            }
            CB_PUTS("</row>\n");
        }
        CB_PUTS("\t\t</database>\n\t</rra>\n");
    }

    CB_PUTS("</rrd>\n");

    rrd_free(&rrd);

    setlocale(LC_NUMERIC, old_locale);

    return rrd_close(rrd_file);

//Undefining the previously defined shortcuts
//See start of this function
#undef CB_PUTS
#undef CB_FMTS
//End of macro undefining

}