X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_open.c;h=46a5fcf412b6b0a2beb41990e49ac97c528d500b;hp=101e3c3d03a27e82770d67d9db6b0f5f53138ad4;hb=586cc1f6f770892aa24f08e38a6c14c2c47ee560;hpb=45f97327ebf242442e2d9dfb8528cae01e300cc1 diff --git a/src/rrd_open.c b/src/rrd_open.c index 101e3c3..46a5fcf 100644 --- a/src/rrd_open.c +++ b/src/rrd_open.c @@ -1,5 +1,5 @@ /***************************************************************************** - * RRDtool 1.3.2 Copyright by Tobi Oetiker, 1997-2008 + * RRDtool 1.4.3 Copyright by Tobi Oetiker, 1997-2010 ***************************************************************************** * rrd_open.c Open an RRD File ***************************************************************************** @@ -8,8 +8,36 @@ #include "rrd_tool.h" #include "unused.h" + +#ifdef WIN32 +#include +#include +#include +#endif + + +#ifdef HAVE_BROKEN_MS_ASYNC +#include +#include +#endif + #define MEMBLK 8192 +#ifdef WIN32 +#define _LK_UNLCK 0 /* Unlock */ +#define _LK_LOCK 1 /* Lock */ +#define _LK_NBLCK 2 /* Non-blocking lock */ +#define _LK_RLCK 3 /* Lock for read only */ +#define _LK_NBRLCK 4 /* Non-blocking lock for read only */ + + +#define LK_UNLCK _LK_UNLCK +#define LK_LOCK _LK_LOCK +#define LK_NBLCK _LK_NBLCK +#define LK_RLCK _LK_RLCK +#define LK_NBRLCK _LK_NBRLCK +#endif + /* DEBUG 2 prints information obtained via mincore(2) */ #define DEBUG 1 /* do not calculate exact madvise hints but assume 1 page for headers and @@ -34,7 +62,7 @@ #define __rrd_read(dst, dst_t, cnt) { \ size_t wanted = sizeof(dst_t)*(cnt); \ size_t got; \ - if ((dst = malloc(wanted)) == NULL) { \ + if ((dst = (dst_t*)malloc(wanted)) == NULL) { \ rrd_set_error(#dst " malloc"); \ goto out_nullify_head; \ } \ @@ -69,9 +97,8 @@ rrd_file_t *rrd_open( rrd_t *rrd, unsigned rdwr) { - int i; + unsigned long ui; int flags = 0; - mode_t mode = S_IRUSR; int version; #ifdef HAVE_MMAP @@ -82,32 +109,24 @@ rrd_file_t *rrd_open( struct stat statb; rrd_file_t *rrd_file = NULL; rrd_simple_file_t *rrd_simple_file = NULL; - off_t newfile_size = 0; - off_t header_len, value_cnt, data_len; + 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 = \ - sizeof(stat_head_t) + \ - sizeof(ds_def_t) * rrd->stat_head->ds_cnt + \ - sizeof(rra_def_t) * rrd->stat_head->rra_cnt + \ - sizeof(time_t) + \ - sizeof(live_head_t) + \ - sizeof(pdp_prep_t) * rrd->stat_head->ds_cnt + \ - sizeof(cdp_prep_t) * rrd->stat_head->ds_cnt * rrd->stat_head->rra_cnt + \ - sizeof(rra_ptr_t) * rrd->stat_head->rra_cnt; + header_len = rrd_get_header_size(rrd); value_cnt = 0; - for (i = 0; i < rrd->stat_head->rra_cnt; i++) - value_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[i].row_cnt; + 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 = malloc(sizeof(rrd_file_t)); + 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; @@ -139,23 +158,27 @@ rrd_file_t *rrd_open( 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) { - mode |= S_IWUSR; flags |= O_RDWR; -#ifdef HAVE_MMAP - rrd_simple_file->mm_flags = MAP_SHARED; - rrd_simple_file->mm_prot |= PROT_WRITE; -#endif +#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 @@ -169,11 +192,26 @@ rrd_file_t *rrd_open( flags |= O_BINARY; #endif - if ((rrd_simple_file->fd = open(file_name, flags, mode)) < 0) { + 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 update + on msync MS_ASYNC, 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)) { @@ -184,9 +222,20 @@ rrd_file_t *rrd_open( 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) == -1) { + rrd_set_error("posix_fallocate '%s': %s", file_name, + rrd_strerror(errno)); + goto out_close; + } +#else lseek(rrd_simple_file->fd, newfile_size - 1, SEEK_SET); - write(rrd_simple_file->fd, "\0", 1); /* poke */ + 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); +#endif } #ifdef HAVE_POSIX_FADVISE /* In general we need no read-ahead when dealing with rrd_files. @@ -207,6 +256,40 @@ rrd_file_t *rrd_open( */ #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); @@ -218,22 +301,20 @@ rrd_file_t *rrd_open( goto out_close; } rrd_simple_file->file_start = data; - if (rdwr & RRD_CREAT) { - memset(data, DNAN, newfile_size - 1); - goto out_done; - } #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_WILLNEED | MADV_SEQUENTIAL); + madvise(data, rrd_file->file_len, MADV_WILLNEED ); + 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); /* the stat_head will be needed soonish, so hint accordingly */ - madvise(data, sizeof(stat_head_t), MADV_WILLNEED | MADV_RANDOM); + madvise(data, sizeof(stat_head_t), MADV_WILLNEED); + madvise(data, sizeof(stat_head_t), MADV_RANDOM); } #endif @@ -311,12 +392,11 @@ rrd_file_t *rrd_open( { unsigned long row_cnt = 0; - unsigned long i; - for (i=0; istat_head->rra_cnt; i++) - row_cnt += rrd->rra_def[i].row_cnt; + for (ui=0; uistat_head->rra_cnt; ui++) + row_cnt += rrd->rra_def[ui].row_cnt; - off_t correct_len = rrd_file->header_len + + 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) @@ -336,6 +416,7 @@ rrd_file_t *rrd_open( if (data != MAP_FAILED) munmap(data, rrd_file->file_len); #endif + close(rrd_simple_file->fd); out_free: free(rrd_file->pvt); @@ -355,7 +436,7 @@ void mincore_print( rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt; #ifdef HAVE_MMAP /* pretty print blocks in core */ - off_t off; + size_t off; unsigned char *vec; ssize_t _page_size = sysconf(_SC_PAGESIZE); @@ -436,10 +517,10 @@ void rrd_dontneed( { rrd_simple_file_t *rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt; #if defined USE_MADVISE || defined HAVE_POSIX_FADVISE - off_t dontneed_start; - off_t rra_start; - off_t active_block; - unsigned long i; + size_t dontneed_start; + size_t rra_start; + size_t active_block; + size_t i; ssize_t _page_size = sysconf(_SC_PAGESIZE); if (rrd_file == NULL) { @@ -501,7 +582,7 @@ void rrd_dontneed( #if defined DEBUG && DEBUG > 1 mincore_print(rrd_file, "after"); #endif -#endif /* without madvise and posix_fadvise ist does not make much sense todo anything */ +#endif /* without madvise and posix_fadvise it does not make much sense todo anything */ } @@ -541,9 +622,11 @@ off_t rrd_seek( int whence) { off_t ret = 0; +#ifndef HAVE_MMAP rrd_simple_file_t *rrd_simple_file; rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt; - +#endif + #ifdef HAVE_MMAP if (whence == SEEK_SET) rrd_file->pos = off; @@ -620,7 +703,7 @@ ssize_t rrd_write( { rrd_simple_file_t *rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt; #ifdef HAVE_MMAP - int old_size = rrd_file->file_len; + size_t old_size = rrd_file->file_len; if (count == 0) return 0; if (buf == NULL) @@ -628,7 +711,7 @@ ssize_t rrd_write( if((rrd_file->pos + count) > old_size) { - rrd_set_error("attempting to write beyond end of file"); + rrd_set_error("attempting to write beyond end of file (%ld + %ld > %ld)",rrd_file->pos, count, old_size); return -1; } memcpy(rrd_simple_file->file_start + rrd_file->pos, buf, count); @@ -644,20 +727,13 @@ ssize_t rrd_write( } -/* flush all data pending to be written to FD. */ - +/* this is a leftover from the old days, it serves no purpose + and is therefore turned into a no-op */ void rrd_flush( - rrd_file_t *rrd_file) + rrd_file_t UNUSED(*rrd_file)) { - rrd_simple_file_t *rrd_simple_file; - rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt; - if (fdatasync(rrd_simple_file->fd) != 0) { - rrd_set_error("flushing fd %d: %s", rrd_simple_file->fd, - rrd_strerror(errno)); - } } - /* Initialize RRD header. */ void rrd_init( @@ -709,3 +785,32 @@ void rrd_freemem( { free(mem); } + +/* + * rra_update informs us about the RRAs being updated + * The low level storage API may use this information for + * aligning RRAs within stripes, or other performance enhancements + */ +void rrd_notify_row( + rrd_file_t UNUSED(*rrd_file), + int UNUSED(rra_idx), + unsigned long UNUSED(rra_row), + time_t UNUSED(rra_time)) +{ +} + +/* + * This function is called when creating a new RRD + * The storage implementation can use this opportunity to select + * a sensible starting row within the file. + * The default implementation is random, to ensure that all RRAs + * don't change to a new disk block at the same time + */ +unsigned long rrd_select_initial_row( + rrd_file_t UNUSED(*rrd_file), + int UNUSED(rra_idx), + rra_def_t *rra + ) +{ + return rrd_random() % rra->row_cnt; +}