diff --git a/program/src/rrd_open.c b/program/src/rrd_open.c
index 101e3c3d03a27e82770d67d9db6b0f5f53138ad4..9c839a157b9f3ac3a77807dc28195305ed257b4a 100644 (file)
--- a/program/src/rrd_open.c
+++ b/program/src/rrd_open.c
/*****************************************************************************
- * 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
*****************************************************************************
#include "rrd_tool.h"
#include "unused.h"
+
+#ifdef WIN32
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
+
+#ifdef HAVE_BROKEN_MS_ASYNC
+#include <sys/types.h>
+#include <utime.h>
+#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
#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; \
} \
rrd_t *rrd,
unsigned rdwr)
{
- int i;
+ unsigned long ui;
int flags = 0;
- mode_t mode = S_IRUSR;
int version;
#ifdef HAVE_MMAP
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;
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
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)) {
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.
*/
#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);
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
{
unsigned long row_cnt = 0;
- unsigned long i;
- for (i=0; i<rrd->stat_head->rra_cnt; i++)
- row_cnt += rrd->rra_def[i].row_cnt;
+ for (ui=0; ui<rrd->stat_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)
if (data != MAP_FAILED)
munmap(data, rrd_file->file_len);
#endif
+
close(rrd_simple_file->fd);
out_free:
free(rrd_file->pvt);
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);
{
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) {
#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 */
}
{
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)
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);
}
-/* 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(
{
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;
+}