[rrd-developers] Re: Creating a rrdtool alter command

Igor Sfiligoi Igor.Sfiligoi at lnf.infn.it
Wed Mar 10 18:45:46 MET 2004


On Wednesday 10 March 2004 10:55, Stanislav Sinyagin wrote:
> > My plan was to code this as a simple C-based extention of rrdtool.
>
> I wouldn't call it simple, in case if you want it to be a really universal
> tool.
>
> Please keep us updated about your progress, I might give some input or even
> coding (though C is not my favorite).
>
> Regards,
> Stanislav
>

I have a first example code working; just the data source adding.
I am posting it as it is since Stanislav seemed to be interested ;)

rrd_alter.c:
#include "rrd_tool.h"


static int add_ds(char*          ds_nam,        /* IN */
		  char*          dst,           /* IN */
		  unsigned long  u_cnt,         /* IN */
		  rrd_value_t    min,           /* IN */
		  rrd_value_t    max,           /* IN */
		  rrd_t         *rrd,           /* IN/OUT */
		  rrd_value_t*  *rra_data       /* IN/OUT */
		  )
{
  unsigned long rra_cnt = rrd->stat_head->rra_cnt;
  size_t old_ds_cnt = rrd->stat_head->ds_cnt;
  size_t new_ds_cnt = old_ds_cnt+1;
  int old_rra_els = 0;
  int new_rra_els = 0;
  rrd_value_t* new_rras;
  cdp_prep_t* new_cdp_prep;
  int ii;
  /* check for duplicate datasource names */
  for(ii=0;ii<old_ds_cnt;ii++){
    if(strcmp(ds_nam,rrd->ds_def[ii].ds_nam) == 0){
      rrd_set_error("Duplicate DS name: %s",ds_nam);
      return(-1);
    }				                                
  }

  if((rrd->ds_def = rrd_realloc(rrd->ds_def,
				new_ds_cnt*sizeof(ds_def_t)))==NULL){
    rrd_set_error("allocating rrd.ds_def");
    return(-1);	
  }
  
  for(ii=0;ii < rra_cnt; ii++) {
    old_rra_els += rrd->rra_def[ii].row_cnt * old_ds_cnt;
    new_rra_els += rrd->rra_def[ii].row_cnt * new_ds_cnt;
  }

  if((rrd->ds_def = rrd_realloc(rrd->ds_def,
				new_ds_cnt*sizeof(ds_def_t)))==NULL){
    rrd_set_error("allocating rrd.ds_def");
    return(-1);	
  }

  if((rrd->pdp_prep = rrd_realloc(rrd->pdp_prep,
				  new_ds_cnt*sizeof(pdp_prep_t)))==NULL){
    rrd_set_error("allocating rrd.pdp_prep");
    return(-1);	
  }

  if((new_rras = (rrd_value_t *) 
malloc(new_rra_els*sizeof(rrd_value_t)))==NULL){
    rrd_set_error("allocating rra_data");
    return(-1);	
  }

  if((new_cdp_prep = (cdp_prep_t *) 
malloc(new_ds_cnt*rra_cnt*sizeof(cdp_prep_t)))==NULL){
    rrd_set_error("allocating rrd.cdp_prep");
    free(new_rras);
    return(-1);	
  }

  /* insert new DS in ds_def */
  memset(&rrd->ds_def[old_ds_cnt], 0, sizeof(ds_def_t));
  memcpy(rrd->ds_def[old_ds_cnt].ds_nam,ds_nam,DS_NAM_SIZE);
  memcpy(rrd->ds_def[old_ds_cnt].dst,dst,DST_SIZE);
  rrd->ds_def[old_ds_cnt].par[DS_mrhb_cnt].u_cnt = u_cnt;
  rrd->ds_def[old_ds_cnt].par[DS_min_val].u_val = min;
  rrd->ds_def[old_ds_cnt].par[DS_max_val].u_val = max;  
  rrd->stat_head->ds_cnt++;	    

  /* insert new DS in pdp_prep */
  memset(&rrd->pdp_prep[old_ds_cnt], 0, sizeof(pdp_prep_t));
  strcpy(rrd->pdp_prep[old_ds_cnt].last_ds,"UNKN");
  
  rrd->pdp_prep[old_ds_cnt].scratch[PDP_val].u_val = 0.0;
  rrd->pdp_prep[old_ds_cnt].scratch[PDP_unkn_sec_cnt].u_cnt = 
    rrd->live_head->last_up % rrd->stat_head->pdp_step;

  {/* populate the cdp_prep with the old values+UNKN for the new elements  */
    for(ii=0;ii < rra_cnt;ii++) {
      long idx = ii*new_ds_cnt+old_ds_cnt;
      memcpy(new_cdp_prep+ii*new_ds_cnt,
	     rrd->cdp_prep+ii*old_ds_cnt,
	     old_ds_cnt*sizeof(cdp_prep_t));
      new_cdp_prep[idx].scratch[CDP_val].u_val = DNAN;
      new_cdp_prep[idx].scratch[CDP_unkn_pdp_cnt].u_cnt = 
	    ((rrd->live_head->last_up -
	     rrd->pdp_prep[idx].scratch[PDP_unkn_sec_cnt].u_cnt)
	    % (rrd->stat_head->pdp_step 
	       * rrd->rra_def[ii].pdp_cnt)) / rrd->stat_head->pdp_step;
    }

    free(rrd->cdp_prep);
    rrd->cdp_prep = new_cdp_prep;
  }
  

  {/* populate the RRAs with the old values+UNKN for the new elements  */
    rrd_value_t *old_ptr = *rra_data;
    rrd_value_t *new_ptr = new_rras;
    long i;
    for(ii=0;ii < rra_cnt;ii++) {
      for (i=0; i<rrd->rra_def[ii].row_cnt; i++) {
	memcpy(new_ptr,old_ptr,old_ds_cnt*sizeof(rrd_value_t));
	new_ptr+=old_ds_cnt;
	old_ptr+=old_ds_cnt;
	*new_ptr = DNAN;
	new_ptr++;
      }
    }

    free(*rra_data);
    *rra_data = new_rras;
  }

  return 0;
}

int
rrd_alter(int argc, char **argv) 
{
    char  *infilename;
    FILE  *infile;
    rrd_t          rrd;
    rrd_value_t   *rra_data;
    int err = 0;

    if (argc<2) {
        rrd_set_error("wrong number of parameters");
        return(-1);
    }

    infilename=argv[1];
    if (rrd_open(infilename, &infile, &rrd, RRD_READWRITE)==-1) {
        rrd_set_error("could not open RRD");
        return(-1);
    }
    if (LockRRD(infile) != 0) {
        rrd_set_error("could not lock original RRD");
        rrd_free(&rrd);
        fclose(infile);
        return(-1);
    }

    {
      int total_els = 0;
      long i;
      for(i=0; 
	  i <  rrd.stat_head->rra_cnt;
	  i++)
	  total_els += rrd.rra_def[i].row_cnt * rrd.stat_head->ds_cnt;
	    
      if ((rra_data = (rrd_value_t *) 
malloc(total_els*sizeof(rrd_value_t)))==NULL) {
	rrd_set_error("allocating rra_data");
	rrd_free(&rrd);
	fclose(infile);
	return(-1);
      }

      fread(rra_data,sizeof(rrd_value_t),total_els,infile); 
    }

    while (err==0){
	static struct option long_options[] =
	{
	    {"data-source-add",      required_argument, 0, 's'},
	    {0,0,0,0}
	};
	int option_index = 0;
	int opt;
	opt = getopt_long(argc-1, argv+1, "s:", 
			  long_options, &option_index);
	
	if (opt == EOF)
	  break;
	
	switch(opt) {
	case 's': {/* New DS */
	    char ds_nam[DS_NAM_SIZE];
	    char dst[DST_SIZE];
	    unsigned long u_cnt;
	    char minstr[20], maxstr[20];
	    rrd_value_t min,max;

	    if (sscanf(optarg,
		       DS_NAM_FMT ":" DST_FMT ":%lu:%18[^:]:%18[^:]",
		       ds_nam,
		       dst,
		       &u_cnt,
		       minstr,maxstr) == 5){
	      if (dst_conv(dst) == -1){
		rrd_set_error("Invalid DST '%s'",dst);
		err = -1;
		break;
	      }

	      if (minstr[0] == 'U' && minstr[1] == 0)
		min = DNAN;
	      else
		min = atof(minstr);
	      
	      if (maxstr[0] == 'U' && maxstr[1] == 0)
		max = DNAN;
	      else
		max  = atof(maxstr);
	      
	      if (! isnan(min) &&
		  ! isnan(max) &&
		  min >= max ) {
		rrd_set_error("min must be less than max in DS definition");
		err = -1;
		break;
	      }
	      err = add_ds(ds_nam,dst,u_cnt,min,max,
			   &rrd,&rra_data);
	    } else {
		rrd_set_error("Error parsing data source description '%s'",optarg);
		err = -1;
		break;
	    }
	    break;
	}
	case '?':
            if (optopt != 0)
                rrd_set_error("unknown option '%c'", optopt);
            else
                rrd_set_error("unknown option '%s'",argv[optind-1]);
	    err = -1;
	    break;
	}
    }
    if (err!=0) {
      free(rra_data);
      rrd_free(&rrd);
      fclose(infile);
      return (-1);		
    }


    /* write back the the data */
    fseek(infile,0,SEEK_SET);
    fwrite(rrd.stat_head, sizeof(stat_head_t), 1, infile);
    fwrite(rrd.ds_def, sizeof(ds_def_t), rrd.stat_head->ds_cnt, infile);
    fwrite(rrd.rra_def, sizeof(rra_def_t), rrd.stat_head->rra_cnt, infile);
    fwrite(rrd.live_head, sizeof(live_head_t),1, infile);
    fwrite(rrd.pdp_prep,sizeof(pdp_prep_t),rrd.stat_head->ds_cnt,infile);
    fwrite(rrd.cdp_prep,sizeof(cdp_prep_t),
	   rrd.stat_head->rra_cnt*rrd.stat_head->ds_cnt,infile);
    fwrite(rrd.rra_ptr,sizeof(rra_ptr_t),rrd.stat_head->rra_cnt,infile);
    {
      int total_els = 0;
      long i;
      for(i=0; 
	  i <  rrd.stat_head->rra_cnt;
	  i++)
	total_els += rrd.rra_def[i].row_cnt * rrd.stat_head->ds_cnt;
      
      fwrite(rra_data,sizeof(rrd_value_t),total_els,infile);
    }
    fflush(infile);
    ftruncate(fileno(infile),ftell(infile));
    
    fclose(infile);


    return 0;
}


--
Unsubscribe mailto:rrd-developers-request at list.ee.ethz.ch?subject=unsubscribe
Help        mailto:rrd-developers-request at list.ee.ethz.ch?subject=help
Archive     http://www.ee.ethz.ch/~slist/rrd-developers
WebAdmin    http://www.ee.ethz.ch/~slist/lsg2.cgi



More information about the rrd-developers mailing list