Ejemplo n.º 1
0
rrd_file_t *rrd_open(
    const char *const file_name,
    rrd_t *rrd,
    unsigned rdwr)
{
    unsigned long ui;
    int       flags = 0;
    int       version;

#ifdef HAVE_MMAP
    char     *data = MAP_FAILED;
#endif
    off_t     offset = 0;
    struct stat statb;
    rrd_file_t *rrd_file = NULL;
    rrd_simple_file_t *rrd_simple_file = NULL;
    size_t     newfile_size = 0;
    size_t header_len, value_cnt, data_len;

    /* Are we creating a new file? */
    if((rdwr & RRD_CREAT) && (rrd->stat_head != NULL))
    {
        header_len = rrd_get_header_size(rrd);

        value_cnt = 0;
        for (ui = 0; ui < rrd->stat_head->rra_cnt; ui++)
            value_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[ui].row_cnt;

        data_len = sizeof(rrd_value_t) * value_cnt;

        newfile_size = header_len + data_len;
    }
    
    rrd_file = (rrd_file_t*)malloc(sizeof(rrd_file_t));
    if (rrd_file == NULL) {
        rrd_set_error("allocating rrd_file descriptor for '%s'", file_name);
        return NULL;
    }
    memset(rrd_file, 0, sizeof(rrd_file_t));
    rrd_file->rrd = rrd;
    
    rrd_file->pvt = malloc(sizeof(rrd_simple_file_t));
    if(rrd_file->pvt == NULL) {
        rrd_set_error("allocating rrd_simple_file for '%s'", file_name);
        return NULL;
    }
    memset(rrd_file->pvt, 0, sizeof(rrd_simple_file_t));
    rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt;

#ifdef DEBUG
    if ((rdwr & (RRD_READONLY | RRD_READWRITE)) ==
        (RRD_READONLY | RRD_READWRITE)) {
        /* Both READONLY and READWRITE were given, which is invalid.  */
        rrd_set_error("in read/write request mask");
        exit(-1);
    }
#endif

#ifdef HAVE_MMAP
    rrd_simple_file->mm_prot = PROT_READ;
    rrd_simple_file->mm_flags = 0;
#endif

    if (rdwr & RRD_READONLY) {
        flags |= O_RDONLY;
#ifdef HAVE_MMAP
# if !defined(AIX)
        rrd_simple_file->mm_flags = MAP_PRIVATE;
# endif
# ifdef MAP_NORESERVE
        rrd_simple_file->mm_flags |= MAP_NORESERVE;  /* readonly, so no swap backing needed */
# endif
#endif
    } else {
        if (rdwr & RRD_READWRITE) {
            flags |= O_RDWR;
#ifdef HAVE_MMAP 
            rrd_simple_file->mm_flags = MAP_SHARED; 
            rrd_simple_file->mm_prot |= PROT_WRITE; 
#endif 
        }
        if (rdwr & RRD_CREAT) {
            flags |= (O_CREAT | O_TRUNC);
        }
        if (rdwr & RRD_EXCL) {
            flags |= O_EXCL;
        }
    }
    if (rdwr & RRD_READAHEAD) {
#ifdef MAP_POPULATE
        rrd_simple_file->mm_flags |= MAP_POPULATE;   /* populate ptes and data */
#endif
#if defined MAP_NONBLOCK
        rrd_simple_file->mm_flags |= MAP_NONBLOCK;   /* just populate ptes */
#endif
    }
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
    flags |= O_BINARY;
#endif

    if ((rrd_simple_file->fd = open(file_name, flags, 0666)) < 0) {
        rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno));
        goto out_free;
    }

#ifdef HAVE_MMAP
#ifdef HAVE_BROKEN_MS_ASYNC
    if (rdwr & RRD_READWRITE) {    
        /* some unices, the files mtime does not get updated
           on memory mapped files, in order to help them,     
           we update the the timestamp at this point.      
           The thing happens pretty 'close' to the open    
           call so the chances of a race should be minimal.    
                
           Maybe ask your vendor to fix your OS ... */    
           utime(file_name,NULL);  
    }
#endif    
#endif

    /* Better try to avoid seeks as much as possible. stat may be heavy but
     * many concurrent seeks are even worse.  */
    if (newfile_size == 0 && ((fstat(rrd_simple_file->fd, &statb)) < 0)) {
        rrd_set_error("fstat '%s': %s", file_name, rrd_strerror(errno));
        goto out_close;
    }
    if (newfile_size == 0) {
        rrd_file->file_len = statb.st_size;
    } else {
        rrd_file->file_len = newfile_size;
#ifdef HAVE_POSIX_FALLOCATE
        if (posix_fallocate(rrd_simple_file->fd, 0, newfile_size) == 0){
            /* if all  is well we skip the seeking below */            
            goto no_lseek_necessary;        
        }
#endif
        lseek(rrd_simple_file->fd, newfile_size - 1, SEEK_SET);
        if ( write(rrd_simple_file->fd, "\0", 1) == -1){    /* poke */
            rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
            goto out_close;
        }
        lseek(rrd_simple_file->fd, 0, SEEK_SET);
    }
    no_lseek_necessary:
#ifdef HAVE_POSIX_FADVISE
    /* In general we need no read-ahead when dealing with rrd_files.
       When we stop reading, it is highly unlikely that we start up again.
       In this manner we actually save time and diskaccess (and buffer cache).
       Thanks to Dave Plonka for the Idea of using POSIX_FADV_RANDOM here. */
    posix_fadvise(rrd_simple_file->fd, 0, 0, POSIX_FADV_RANDOM);
#endif

/*
        if (rdwr & RRD_READWRITE)
        {
           if (setvbuf((rrd_simple_file->fd),NULL,_IONBF,2)) {
                  rrd_set_error("failed to disable the stream buffer\n");
                  return (-1);
           }
        }
*/

#ifdef HAVE_MMAP
#ifndef HAVE_POSIX_FALLOCATE
	/* force allocating the file on the underlaying filesystem to prevent any
	 * future bus error when the filesystem is full and attempting to write
	 * trough the file mapping. Filling the file using memset on the file
	 * mapping can also lead some bus error, so we use the old fashioned
	 * write().
	 */
    if (rdwr & RRD_CREAT) {
		char     buf[4096];
		unsigned i;

		memset(buf, DNAN, sizeof buf);
		lseek(rrd_simple_file->fd, offset, SEEK_SET);
        
		for (i = 0; i < (newfile_size - 1) / sizeof buf; ++i)
		{
			if (write(rrd_simple_file->fd, buf, sizeof buf) == -1)
			{
				rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
				goto out_close;
			}
		}
		
		if (write(rrd_simple_file->fd, buf,
					(newfile_size - 1) % sizeof buf) == -1)
		{
			rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
			goto out_close;
		}

		lseek(rrd_simple_file->fd, 0, SEEK_SET);
    }
#endif

    data = mmap(0, rrd_file->file_len, 
        rrd_simple_file->mm_prot, rrd_simple_file->mm_flags,
        rrd_simple_file->fd, offset);

    /* lets see if the first read worked */
    if (data == MAP_FAILED) {
        rrd_set_error("mmaping file '%s': %s", file_name,
                      rrd_strerror(errno));
        goto out_close;
    }
    rrd->__mmap_start = data;
    rrd->__mmap_size  = rrd_file->file_len;
	    
    rrd_simple_file->file_start = data;
#endif
    if (rdwr & RRD_CREAT)
        goto out_done;
#ifdef USE_MADVISE
    if (rdwr & RRD_COPY) {
        /* We will read everything in a moment (copying) */
        madvise(data, rrd_file->file_len, MADV_SEQUENTIAL );
    } else {
        /* We do not need to read anything in for the moment */
        madvise(data, rrd_file->file_len, MADV_RANDOM);
    }
#endif

    __rrd_read(rrd->stat_head, stat_head_t,
               1);

    /* lets do some test if we are on track ... */
    if (memcmp(rrd->stat_head->cookie, RRD_COOKIE, sizeof(RRD_COOKIE)) != 0) {
        rrd_set_error("'%s' is not an RRD file", file_name);
        goto out_nullify_head;
    }

    if (rrd->stat_head->float_cookie != FLOAT_COOKIE) {
        rrd_set_error("This RRD was created on another architecture");
        goto out_nullify_head;
    }

    version = atoi(rrd->stat_head->version);

    if (version > atoi(RRD_VERSION)) {
        rrd_set_error("can't handle RRD file version %s",
                      rrd->stat_head->version);
        goto out_nullify_head;
    }
    __rrd_read(rrd->ds_def, ds_def_t,
               rrd->stat_head->ds_cnt);

    __rrd_read(rrd->rra_def, rra_def_t,
               rrd->stat_head->rra_cnt);

    /* handle different format for the live_head */
    if (version < 3) {
        rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t));
        if (rrd->live_head == NULL) {
            rrd_set_error("live_head_t malloc");
            goto out_close;
        }
        __rrd_read(rrd->legacy_last_up, time_t,
                   1);

        rrd->live_head->last_up = *rrd->legacy_last_up;
        rrd->live_head->last_up_usec = 0;
    } else {
        __rrd_read(rrd->live_head, live_head_t,
                   1);
    }
    __rrd_read(rrd->pdp_prep, pdp_prep_t,
               rrd->stat_head->ds_cnt);
    __rrd_read(rrd->cdp_prep, cdp_prep_t,
               rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt);
    __rrd_read(rrd->rra_ptr, rra_ptr_t,
               rrd->stat_head->rra_cnt);

    rrd_file->header_len = offset;
    rrd_file->pos = offset;

    {
      unsigned long row_cnt = 0;

      for (ui=0; ui<rrd->stat_head->rra_cnt; ui++)
        row_cnt += rrd->rra_def[ui].row_cnt;

      size_t  correct_len = rrd_file->header_len +
        sizeof(rrd_value_t) * row_cnt * rrd->stat_head->ds_cnt;

      if (correct_len > rrd_file->file_len)
      {
        rrd_set_error("'%s' is too small (should be %ld bytes)",
                      file_name, (long long) correct_len);
        goto out_nullify_head;
      }
      if (rdwr & RRD_READVALUES) {
	  long d_offset = offset;
	  
	  __rrd_read(rrd->rrd_value, rrd_value_t,
		     row_cnt * rrd->stat_head->ds_cnt);

	  rrd_file->header_len = d_offset;
	  rrd_file->pos = d_offset;
      }
      
    }

    
    
  out_done:
    return (rrd_file);
  out_nullify_head:
    rrd->stat_head = NULL;
  out_close:
#ifdef HAVE_MMAP
    if (data != MAP_FAILED)
      munmap(data, rrd_file->file_len);
    rrd->__mmap_start = NULL;
    rrd->__mmap_size = 0;
#endif

    close(rrd_simple_file->fd);
  out_free:
    free(rrd_file->pvt);
    free(rrd_file);
    return NULL;
}
Ejemplo n.º 2
0
rrd_info_t *rrd_info_r(
    const 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);
}