X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_update.c;h=489c35901cbdd68d67dc0294223fdaa7b0b9cb18;hp=6ba9fdb0233f81dea3633fefe777515bf9f466f8;hb=b02eace34f83a08c55830cb05bc55078153e2ba6;hpb=134ab7800aa5ee81007b7467a56e6f46a5017b85 diff --git a/src/rrd_update.c b/src/rrd_update.c index 6ba9fdb..489c359 100644 --- a/src/rrd_update.c +++ b/src/rrd_update.c @@ -1,66 +1,19 @@ /***************************************************************************** - * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002 + * RRDtool 1.2rc4 Copyright by Tobi Oetiker, 1997-2005 ***************************************************************************** * rrd_update.c RRD Update Function ***************************************************************************** * $Id$ - * $Log$ - * Revision 1.8 2003/03/31 21:22:12 oetiker - * enables RRDtool updates with microsecond or in case of windows millisecond - * precision. This is needed to reduce time measurement error when archive step - * is small. (<30s) -- Sasha Mikheev - * - * Revision 1.7 2003/02/13 07:05:27 oetiker - * Find attached the patch I promised to send to you. Please note that there - * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c - * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This - * library is identical to librrd, but it contains support code for per-thread - * global variables currently used for error information only. This is similar - * to how errno per-thread variables are implemented. librrd_th must be linked - * alongside of libpthred - * - * There is also a new file "THREADS", holding some documentation. - * - * -- Peter Stamfest - * - * Revision 1.6 2002/02/01 20:34:49 oetiker - * fixed version number and date/time - * - * Revision 1.5 2001/05/09 05:31:01 oetiker - * Bug fix: when update of multiple PDP/CDP RRAs coincided - * with interpolation of multiple PDPs an incorrect value was - * stored as the CDP. Especially evident for GAUGE data sources. - * Minor changes to rrdcreate.pod. -- Jake Brutlag - * - * Revision 1.4 2001/03/10 23:54:41 oetiker - * Support for COMPUTE data sources (CDEF data sources). Removes the RPN - * parser and calculator from rrd_graph and puts then in a new file, - * rrd_rpncalc.c. Changes to core files rrd_create and rrd_update. Some - * clean-up of aberrant behavior stuff, including a bug fix. - * Documentation update (rrdcreate.pod, rrdupdate.pod). Change xml format. - * -- Jake Brutlag - * - * Revision 1.3 2001/03/04 13:01:55 oetiker - * Aberrant Behavior Detection support. A brief overview added to rrdtool.pod. - * Major updates to rrd_update.c, rrd_create.c. Minor update to other core files. - * This is backwards compatible! But new files using the Aberrant stuff are not readable - * by old rrdtool versions. See http://cricket.sourceforge.net/aberrant/rrd_hw.htm - * -- Jake Brutlag - * - * Revision 1.2 2001/03/04 11:14:25 oetiker - * added at-style-time@value:value syntax to rrd_update - * -- Dave Bodenstab - * - * Revision 1.1.1.1 2001/02/25 22:25:06 oetiker - * checkin - * *****************************************************************************/ #include "rrd_tool.h" #include #include +#ifdef HAVE_MMAP + #include +#endif -#ifdef WIN32 +#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) #include #include #include @@ -71,7 +24,7 @@ #include "rrd_is_thread_safe.h" -#ifdef WIN32 +#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) /* * WIN32 does not have gettimeofday and struct timeval. This is a quick and dirty * replacement. @@ -113,10 +66,20 @@ static void normalize_time(struct timeval *t) /* Local prototypes */ int LockRRD(FILE *rrd_file); -void write_RRA_row (rrd_t *rrd, unsigned long rra_idx, +#ifdef HAVE_MMAP +info_t *write_RRA_row (rrd_t *rrd, unsigned long rra_idx, + unsigned long *rra_current, + unsigned short CDP_scratch_idx, FILE *rrd_file, + info_t *pcdp_summary, time_t *rra_time, void *rrd_mmaped_file); +#else +info_t *write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, - unsigned short CDP_scratch_idx, FILE *rrd_file); + unsigned short CDP_scratch_idx, FILE *rrd_file, + info_t *pcdp_summary, time_t *rra_time); +#endif int rrd_update_r(char *filename, char *template, int argc, char **argv); +int _rrd_update(char *filename, char *template, int argc, char **argv, + info_t*); #define IFDNAN(X,Y) (isnan(X) ? (Y) : (X)); @@ -126,7 +89,7 @@ int main(int argc, char **argv){ rrd_update(argc,argv); if (rrd_test_error()) { - printf("RRDtool 1.1.x Copyright 1997-2000 by Tobias Oetiker \n\n" + printf("RRDtool 1.2rc4 Copyright by Tobi Oetiker, 1997-2005\n\n" "Usage: rrdupdate filename\n" "\t\t\t[--template|-t ds-name:ds-name:...]\n" "\t\t\ttime|N:value[:value...]\n\n" @@ -141,6 +104,52 @@ main(int argc, char **argv){ } #endif +info_t *rrd_update_v(int argc, char **argv) +{ + char *template = NULL; + info_t *result = NULL; + infoval rc; + + while (1) { + static struct option long_options[] = + { + {"template", required_argument, 0, 't'}, + {0,0,0,0} + }; + int option_index = 0; + int opt; + opt = getopt_long(argc, argv, "t:", + long_options, &option_index); + + if (opt == EOF) + break; + + switch(opt) { + case 't': + template = optarg; + break; + + case '?': + rrd_set_error("unknown option '%s'",argv[optind-1]); + rc.u_int = -1; + goto end_tag; + } + } + + /* need at least 2 arguments: filename, data. */ + if (argc-optind < 2) { + rrd_set_error("Not enough arguments"); + rc.u_int = -1; + goto end_tag; + } + result = info_push(NULL,sprintf_alloc("return_value"),RD_I_INT,rc); + rc.u_int = _rrd_update(argv[optind], template, + argc - optind - 1, argv + optind + 1, result); + result->value.u_int = rc.u_int; +end_tag: + return result; +} + int rrd_update(int argc, char **argv) { @@ -165,7 +174,7 @@ rrd_update(int argc, char **argv) case 't': template = optarg; break; - + case '?': rrd_set_error("unknown option '%s'",argv[optind-1]); return(-1); @@ -178,8 +187,8 @@ rrd_update(int argc, char **argv) return -1; } - - rc = rrd_update_r(argv[optind], template, + + rc = rrd_update_r(argv[optind], template, argc - optind - 1, argv + optind + 1); return rc; } @@ -187,6 +196,13 @@ rrd_update(int argc, char **argv) int rrd_update_r(char *filename, char *template, int argc, char **argv) { + return _rrd_update(filename, template, argc, argv, NULL); +} + +int +_rrd_update(char *filename, char *template, int argc, char **argv, + info_t *pcdp_summary) +{ int arg_i = 2; short j; @@ -229,6 +245,7 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) FILE *rrd_file; rrd_t rrd; time_t current_time; + time_t rra_time; /* time of update for a RRA */ unsigned long current_time_usec; /* microseconds part of current time */ struct timeval tmp_time; /* used for time conversion */ @@ -251,6 +268,11 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) /* numeric id of the current consolidation function */ rpnstack_t rpnstack; /* used for COMPUTE DS */ int version; /* rrd version */ + char *endptr; /* used in the conversion */ +#ifdef HAVE_MMAP + void *rrd_mmaped_file; + unsigned long rrd_filesize; +#endif rpnstack_init(&rpnstack); @@ -287,7 +309,13 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) followed by output without an intervening call to a file positioning function, unless the input oepration encounters end-of-file. */ +#ifdef HAVE_MMAP + fseek(rrd_file, 0, SEEK_END); + rrd_filesize = ftell(rrd_file); + fseek(rrd_file, rra_current, SEEK_SET); +#else fseek(rrd_file, 0, SEEK_CUR); +#endif /* get exclusive lock to whole file. @@ -384,6 +412,23 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) return(-1); } +#ifdef HAVE_MMAP + rrd_mmaped_file = mmap(0, + rrd_filesize, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fileno(rrd_file), + 0); + if (rrd_mmaped_file == MAP_FAILED) { + rrd_set_error("error mmapping file %s", filename); + free(updvals); + free(pdp_temp); + free(tmpl_idx); + rrd_free(&rrd); + fclose(rrd_file); + return(-1); + } +#endif /* loop through the arguments. */ for(arg_i=0; arg_i '9' || (ii==0 && updvals[i+1][ii] == '-')){ + rrd_set_error("not a simple integer: '%s'",updvals[i+1]); + break; + } + } + if (rrd_test_error()){ + break; + } pdp_new[i]= rrd_diff(updvals[i+1],rrd.pdp_prep[i].last_ds); if(dst_idx == DST_COUNTER) { - /* simple overflow catcher sugestet by andres kroonmaa */ + /* simple overflow catcher suggested by Andres Kroonmaa */ /* this will fail terribly for non 32 or 64 bit counters ... */ /* are there any others in SNMP land ? */ if (pdp_new[i] < (double)0.0 ) @@ -572,11 +631,29 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) } break; case DST_ABSOLUTE: - pdp_new[i]= atof(updvals[i+1]); + errno = 0; + pdp_new[i] = strtod(updvals[i+1],&endptr); + if (errno > 0){ + rrd_set_error("converting '%s' to float: %s",updvals[i+1],rrd_strerror(errno)); + break; + }; + if (endptr[0] != '\0'){ + rrd_set_error("conversion of '%s' to float not complete: tail '%s'",updvals[i+1],endptr); + break; + } rate = pdp_new[i] / interval; break; case DST_GAUGE: - pdp_new[i] = atof(updvals[i+1]) * interval; + errno = 0; + pdp_new[i] = strtod(updvals[i+1],&endptr) * interval; + if (errno > 0){ + rrd_set_error("converting '%s' to float: %s",updvals[i+1],rrd_strerror(errno)); + break; + }; + if (endptr[0] != '\0'){ + rrd_set_error("conversion of '%s' to float not complete: tail '%s'",updvals[i+1],endptr); + break; + } rate = pdp_new[i] / interval; break; default: @@ -1098,10 +1175,12 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) rra_pos_tmp = rra_start + (rrd.stat_head->ds_cnt)*(rrd.rra_ptr[i].cur_row)*sizeof(rrd_value_t); if(rra_pos_tmp != rra_current) { +#ifndef HAVE_MMAP if(fseek(rrd_file, rra_pos_tmp, SEEK_SET) != 0){ rrd_set_error("seek error in rrd"); break; } +#endif rra_current = rra_pos_tmp; } @@ -1109,15 +1188,26 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) fprintf(stderr," -- RRA Postseek %ld\n",ftell(rrd_file)); #endif scratch_idx = CDP_primary_val; - write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file); + if (pcdp_summary != NULL) + { + rra_time = (current_time - current_time + % (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) + - ((rra_step_cnt[i]-1)*rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step); + } +#ifdef HAVE_MMAP + pcdp_summary = write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file, + pcdp_summary, &rra_time, rrd_mmaped_file); +#else + pcdp_summary = write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file, + pcdp_summary, &rra_time); +#endif if (rrd_test_error()) break; /* write other rows of the bulk update, if any */ scratch_idx = CDP_secondary_val; - for ( ; rra_step_cnt[i] > 1; - rra_step_cnt[i]--, rrd.rra_ptr[i].cur_row++) + for ( ; rra_step_cnt[i] > 1; rra_step_cnt[i]--) { - if (rrd.rra_ptr[i].cur_row == rrd.rra_def[i].row_cnt) + if (++rrd.rra_ptr[i].cur_row == rrd.rra_def[i].row_cnt) { #ifdef DEBUG fprintf(stderr,"Wraparound for RRA %s, %lu updates left\n", @@ -1136,7 +1226,19 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) #endif rra_current = rra_start; } - write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file); + if (pcdp_summary != NULL) + { + rra_time = (current_time - current_time + % (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) + - ((rra_step_cnt[i]-2)*rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step); + } +#ifdef HAVE_MMAP + pcdp_summary = write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file, + pcdp_summary, &rra_time, rrd_mmaped_file); +#else + pcdp_summary = write_RRA_row(&rrd, i, &rra_current, scratch_idx, rrd_file, + pcdp_summary, &rra_time); +#endif } if (rrd_test_error()) @@ -1160,6 +1262,11 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) if (rra_step_cnt != NULL) free(rra_step_cnt); rpnstack_free(&rpnstack); +#ifdef HAVE_MMAP + if (munmap(rrd_mmaped_file, rrd_filesize) == -1) { + rrd_set_error("error writing(unmapping) file: %s", filename); + } +#endif /* if we got here and if there is an error and if the file has not been * written to, then close things up and return. */ if (rrd_test_error()) { @@ -1276,10 +1383,10 @@ rrd_update_r(char *filename, char *template, int argc, char **argv) * critical except during the burning cycles. */ if (schedule_smooth) { -#ifndef WIN32 - rrd_file = fopen(filename,"r+"); -#else +#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) rrd_file = fopen(filename,"rb+"); +#else + rrd_file = fopen(filename,"r+"); #endif rra_start = rra_begin; for (i = 0; i < rrd.stat_head -> rra_cnt; ++i) @@ -1317,40 +1424,49 @@ int LockRRD(FILE *rrdfile) { int rrd_fd; /* File descriptor for RRD */ - int stat; + int rcstat; rrd_fd = fileno(rrdfile); { -#ifndef WIN32 - struct flock lock; +#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) + struct _stat st; + + if ( _fstat( rrd_fd, &st ) == 0 ) { + rcstat = _locking ( rrd_fd, _LK_NBLCK, st.st_size ); + } else { + rcstat = -1; + } +#else + struct flock lock; lock.l_type = F_WRLCK; /* exclusive write lock */ lock.l_len = 0; /* whole file */ lock.l_start = 0; /* start of file */ lock.l_whence = SEEK_SET; /* end of file */ - stat = fcntl(rrd_fd, F_SETLK, &lock); -#else - struct _stat st; - - if ( _fstat( rrd_fd, &st ) == 0 ) { - stat = _locking ( rrd_fd, _LK_NBLCK, st.st_size ); - } else { - stat = -1; - } + rcstat = fcntl(rrd_fd, F_SETLK, &lock); #endif } - return(stat); + return(rcstat); } -void -write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, - unsigned short CDP_scratch_idx, FILE *rrd_file) +#ifdef HAVE_MMAP +info_t +*write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, + unsigned short CDP_scratch_idx, FILE *rrd_file, + info_t *pcdp_summary, time_t *rra_time, void *rrd_mmaped_file) +#else +info_t +*write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, + unsigned short CDP_scratch_idx, FILE *rrd_file, + info_t *pcdp_summary, time_t *rra_time) +#endif { unsigned long ds_idx, cdp_idx; - + infoval iv; + for (ds_idx = 0; ds_idx < rrd -> stat_head -> ds_cnt; ds_idx++) { /* compute the cdp index */ @@ -1360,13 +1476,29 @@ write_RRA_row (rrd_t *rrd, unsigned long rra_idx, unsigned long *rra_current, rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val,ftell(rrd_file), rrd -> rra_def[rra_idx].cf_nam); #endif - + if (pcdp_summary != NULL) + { + iv.u_val = rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val; + /* append info to the return hash */ + pcdp_summary = info_push(pcdp_summary, + sprintf_alloc("[%d]RRA[%s][%lu]DS[%s]", + *rra_time, rrd->rra_def[rra_idx].cf_nam, + rrd->rra_def[rra_idx].pdp_cnt, rrd->ds_def[ds_idx].ds_nam), + RD_I_VAL, iv); + } +#ifdef HAVE_MMAP + memcpy((char *)rrd_mmaped_file + *rra_current, + &(rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val), + sizeof(rrd_value_t)); +#else if(fwrite(&(rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val), sizeof(rrd_value_t),1,rrd_file) != 1) { rrd_set_error("writing rrd"); - return; + return 0; } +#endif *rra_current += sizeof(rrd_value_t); } + return (pcdp_summary); }