added --no-overwrite option to rrdtool create. It prevents rrdtool from clobbering...
[rrdtool.git] / src / rrd_open.c
index a83031a..0939e7c 100644 (file)
@@ -1,15 +1,41 @@
 /*****************************************************************************
- * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2008
+ * RRDtool 1.4.2  Copyright by Tobi Oetiker, 1997-2009
  *****************************************************************************
  * rrd_open.c  Open an RRD File
  *****************************************************************************
  * $Id$
  *****************************************************************************/
 
+#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
+
 #include "rrd_tool.h"
 #include "unused.h"
 #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 +60,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,7 +95,7 @@ rrd_file_t *rrd_open(
     rrd_t *rrd,
     unsigned rdwr)
 {
-    int i;
+    unsigned long ui;
     int       flags = 0;
     int       version;
 
@@ -81,32 +107,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;
@@ -146,14 +164,17 @@ rrd_file_t *rrd_open(
     } 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
+#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
@@ -172,6 +193,21 @@ rrd_file_t *rrd_open(
         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)) {
@@ -183,7 +219,10 @@ rrd_file_t *rrd_open(
     } else {
         rrd_file->file_len = newfile_size;
         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);
     }
 #ifdef HAVE_POSIX_FADVISE
@@ -226,12 +265,14 @@ rrd_file_t *rrd_open(
 #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
 
@@ -309,12 +350,11 @@ rrd_file_t *rrd_open(
 
     {
       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)
@@ -334,6 +374,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);
@@ -353,7 +394,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);
 
@@ -434,10 +475,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) {
@@ -499,7 +540,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 */
 }
 
 
@@ -618,7 +659,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)
@@ -642,20 +683,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 *rrd_file  __attribute__((unused)))
 {
-    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(
@@ -707,3 +741,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 *rrd_file  __attribute__((unused)),
+    int rra_idx  __attribute__((unused)),
+    unsigned long rra_row  __attribute__((unused)),
+    time_t rra_time  __attribute__((unused)))
+{
+}
+
+/*
+ * 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 *rrd_file  __attribute__((unused)),
+    int rra_idx  __attribute__((unused)),
+    rra_def_t *rra
+    )
+{
+    return rrd_random() % rra->row_cnt;
+}