This patch introduces a feature whereby rrdcached will disallow updates
[rrdtool.git] / src / rrd_open.c
index c6a2d7d..f262413 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.2.99907080300  Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2008
  *****************************************************************************
  * rrd_open.c  Open an RRD File
  *****************************************************************************
 /* the cast to void* is there to avoid this warning seen on ia64 with certain
    versions of gcc: 'cast increases required alignment of target type'
 */
-#define __rrd_read(dst, dst_t, cnt) \
+#define __rrd_read(dst, dst_t, cnt) { \
+       size_t wanted = sizeof(dst_t)*(cnt); \
+       if (offset + wanted > rrd_file->file_len) { \
+               rrd_set_error("reached EOF while loading header " #dst); \
+               goto out_nullify_head; \
+       } \
        (dst) = (dst_t*)(void*) (data + offset); \
-       offset += sizeof(dst_t) * (cnt)
+       offset += wanted; \
+    }
 #else
-#define __rrd_read(dst, dst_t, cnt) \
-       if ((dst = malloc(sizeof(dst_t)*(cnt))) == NULL) { \
+#define __rrd_read(dst, dst_t, cnt) { \
+       size_t wanted = sizeof(dst_t)*(cnt); \
+        size_t got; \
+       if ((dst = malloc(wanted)) == NULL) { \
                rrd_set_error(#dst " malloc"); \
                goto out_nullify_head; \
        } \
-       offset += read (rrd_file->fd, dst, sizeof(dst_t)*(cnt))
+        got = read (rrd_file->fd, dst, wanted); \
+       if (got != wanted) { \
+               rrd_set_error("short read while reading header " #dst); \
+                goto out_nullify_head; \
+       } \
+       offset += got; \
+    }
 #endif
 
 /* get the address of the start of this page */
+#if defined USE_MADVISE || defined HAVE_POSIX_FADVISE
 #ifndef PAGE_START
 #define PAGE_START(addr) ((addr)&(~(_page_size-1)))
 #endif
-
+#endif
 
 /* Open a database file, return its header and an open filehandle,
  * positioned to the first cdp in the first rra.
@@ -57,7 +72,7 @@ rrd_file_t *rrd_open(
 #ifdef HAVE_MMAP
     ssize_t   _page_size = sysconf(_SC_PAGESIZE);
     int       mm_prot = PROT_READ, mm_flags = 0;
-    char     *data;
+    char     *data = MAP_FAILED;
 #endif
     off_t     offset = 0;
     struct stat statb;
@@ -115,6 +130,9 @@ rrd_file_t *rrd_open(
         mm_flags |= MAP_NONBLOCK;   /* just populate ptes */
 #endif
     }
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+    flags |= O_BINARY;
+#endif
 
     if ((rrd_file->fd = open(file_name, flags, mode)) < 0) {
         rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno));
@@ -140,11 +158,7 @@ rrd_file_t *rrd_open(
        When we stop reading, it is highly unlikely that we start up again.
        In this manner we actually save time and diskaccess (and buffer cache).
        Thanks to Dave Plonka for the Idea of using POSIX_FADV_RANDOM here. */
-    if (0 != posix_fadvise(rrd_file->fd, 0, 0, POSIX_FADV_RANDOM)) {
-        rrd_set_error("setting POSIX_FADV_RANDOM on '%s': %s", file_name,
-                      rrd_strerror(errno));
-        goto out_close;
-    }
+    posix_fadvise(rrd_file->fd, 0, 0, POSIX_FADV_RANDOM);
 #endif
 
 /*
@@ -230,12 +244,14 @@ rrd_file_t *rrd_open(
             rrd_set_error("live_head_t malloc");
             goto out_close;
         }
-#ifdef HAVE_MMAP
-        memmove(&rrd->live_head->last_up, data + offset, sizeof(long));
-        offset += sizeof(long);
-#else
-        offset += read(rrd_file->fd, &rrd->live_head->last_up, sizeof(long));
+#if defined USE_MADVISE
+        /* the live_head will be needed soonish, so hint accordingly */
+        madvise(data + PAGE_START(offset), sizeof(time_t), MADV_WILLNEED);
 #endif
+        __rrd_read(rrd->legacy_last_up, time_t,
+                   1);
+
+        rrd->live_head->last_up = *rrd->legacy_last_up;
         rrd->live_head->last_up_usec = 0;
     } else {
 #if defined USE_MADVISE
@@ -246,25 +262,43 @@ rrd_file_t *rrd_open(
         __rrd_read(rrd->live_head, live_head_t,
                    1);
     }
-//XXX: This doesn't look like it needs madvise
     __rrd_read(rrd->pdp_prep, pdp_prep_t,
                rrd->stat_head->ds_cnt);
-
-//XXX: This could benefit from madvise()ing
     __rrd_read(rrd->cdp_prep, cdp_prep_t,
                rrd->stat_head->rra_cnt * rrd->stat_head->ds_cnt);
-
-//XXX: This could benefit from madvise()ing
     __rrd_read(rrd->rra_ptr, rra_ptr_t,
                rrd->stat_head->rra_cnt);
 
     rrd_file->header_len = offset;
     rrd_file->pos = offset;
+
+    {
+      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;
+
+      off_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)
+      {
+        rrd_set_error("'%s' is too small (should be %ld bytes)",
+                      file_name, (long long) correct_len);
+        goto out_nullify_head;
+      }
+    }
+
   out_done:
     return (rrd_file);
   out_nullify_head:
     rrd->stat_head = NULL;
   out_close:
+#ifdef HAVE_MMAP
+    if (data != MAP_FAILED)
+      munmap(data, rrd_file->file_len);
+#endif
     close(rrd_file->fd);
   out_free:
     free(rrd_file);
@@ -272,7 +306,8 @@ rrd_file_t *rrd_open(
 }
 
 
-/* Close a reference to an rrd_file.  */
+#if defined DEBUG && DEBUG > 1
+/* Print list of in-core pages of a the current rrd_file.  */
 static
 void mincore_print(
     rrd_file_t *rrd_file,
@@ -314,6 +349,7 @@ void mincore_print(
     fprintf(stderr, "sorry mincore only works with mmap");
 #endif
 }
+#endif                          /* defined DEBUG && DEBUG > 1 */
 
 
 /* drop cache except for the header and the active pages */
@@ -321,12 +357,20 @@ void rrd_dontneed(
     rrd_file_t *rrd_file,
     rrd_t *rrd)
 {
-    unsigned long dontneed_start;
-    unsigned long rra_start;
-    unsigned long active_block;
+#if defined USE_MADVISE || defined HAVE_POSIX_FADVISE
+    off_t dontneed_start;
+    off_t rra_start;
+    off_t active_block;
     unsigned long i;
     ssize_t   _page_size = sysconf(_SC_PAGESIZE);
 
+    if (rrd_file == NULL) {
+#if defined DEBUG && DEBUG
+           fprintf (stderr, "rrd_dontneed: Argument 'rrd_file' is NULL.\n");
+#endif
+           return;
+    }
+
 #if defined DEBUG && DEBUG > 1
     mincore_print(rrd_file, "before");
 #endif
@@ -352,7 +396,8 @@ void rrd_dontneed(
 #endif
         }
         dontneed_start = active_block;
-        /* do not relase 'hot' block if update for this RAA will occure within 10 minutes */
+        /* do not release 'hot' block if update for this RAA will occur
+         * within 10 minutes */
         if (rrd->stat_head->pdp_step * rrd->rra_def[i].pdp_cnt -
             rrd->live_head->last_up % (rrd->stat_head->pdp_step *
                                        rrd->rra_def[i].pdp_cnt) < 10 * 60) {
@@ -362,25 +407,38 @@ void rrd_dontneed(
             rrd->rra_def[i].row_cnt * rrd->stat_head->ds_cnt *
             sizeof(rrd_value_t);
     }
+
+    if (dontneed_start < rrd_file->file_len) {
 #ifdef USE_MADVISE
-    madvise(rrd_file->file_start + dontneed_start,
-            rrd_file->file_len - dontneed_start, MADV_DONTNEED);
+           madvise(rrd_file->file_start + dontneed_start,
+                   rrd_file->file_len - dontneed_start, MADV_DONTNEED);
 #endif
 #ifdef HAVE_POSIX_FADVISE
-    posix_fadvise(rrd_file->fd, dontneed_start,
-                  rrd_file->file_len - dontneed_start, POSIX_FADV_DONTNEED);
+           posix_fadvise(rrd_file->fd, dontneed_start,
+                         rrd_file->file_len - dontneed_start,
+                         POSIX_FADV_DONTNEED);
 #endif
+    }
+
 #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 */
 }
 
+
+
+
+
 int rrd_close(
     rrd_file_t *rrd_file)
 {
     int       ret;
 
 #ifdef HAVE_MMAP
+    ret = msync(rrd_file->file_start, rrd_file->file_len, MS_ASYNC);
+    if (ret != 0)
+        rrd_set_error("msync rrd_file: %s", rrd_strerror(errno));
     ret = munmap(rrd_file->file_start, rrd_file->file_len);
     if (ret != 0)
         rrd_set_error("munmap rrd_file: %s", rrd_strerror(errno));
@@ -416,24 +474,24 @@ off_t rrd_seek(
         rrd_set_error("lseek: %s", rrd_strerror(errno));
     rrd_file->pos = ret;
 #endif
-//XXX: mimic fseek, which returns 0 upon success
-    return ret == -1;   //XXX: or just ret to mimic lseek
+    /* mimic fseek, which returns 0 upon success */
+    return ret < 0;     /*XXX: or just ret to mimic lseek */
 }
 
 
 /* Get current position in rrd_file.  */
 
-inline off_t rrd_tell(
+off_t rrd_tell(
     rrd_file_t *rrd_file)
 {
     return rrd_file->pos;
 }
 
 
-/* read count bytes into buffer buf, starting at rrd_file->pos.
+/* Read count bytes into buffer buf, starting at rrd_file->pos.
  * Returns the number of bytes read or <0 on error.  */
 
-inline ssize_t rrd_read(
+ssize_t rrd_read(
     rrd_file_t *rrd_file,
     void *buf,
     size_t count)
@@ -442,10 +500,10 @@ inline ssize_t rrd_read(
     size_t    _cnt = count;
     ssize_t   _surplus;
 
-    if (rrd_file->pos > rrd_file->file_len || _cnt == 0) /* EOF */
-       return 0;
+    if (rrd_file->pos > rrd_file->file_len || _cnt == 0)    /* EOF */
+        return 0;
     if (buf == NULL)
-       return -1; /* EINVAL */
+        return -1;      /* EINVAL */
     _surplus = rrd_file->pos + _cnt - rrd_file->file_len;
     if (_surplus > 0) { /* short read */
         _cnt -= _surplus;
@@ -467,16 +525,20 @@ inline ssize_t rrd_read(
 }
 
 
-/* write count bytes from buffer buf to the current position
+/* Write count bytes from buffer buf to the current position
  * rrd_file->pos of rrd_file->fd.
- * Returns the number of bytes written.  */
+ * Returns the number of bytes written or <0 on error.  */
 
-inline ssize_t rrd_write(
+ssize_t rrd_write(
     rrd_file_t *rrd_file,
     const void *buf,
     size_t count)
 {
 #ifdef HAVE_MMAP
+    if (count == 0)
+        return 0;
+    if (buf == NULL)
+        return -1;      /* EINVAL */
     memcpy(rrd_file->file_start + rrd_file->pos, buf, count);
     rrd_file->pos += count;
     return count;       /* mimmic write() semantics */
@@ -492,7 +554,7 @@ inline ssize_t rrd_write(
 
 /* flush all data pending to be written to FD.  */
 
-inline void rrd_flush(
+void rrd_flush(
     rrd_file_t *rrd_file)
 {
     if (fdatasync(rrd_file->fd) != 0) {
@@ -511,6 +573,7 @@ void rrd_init(
     rrd->ds_def = NULL;
     rrd->rra_def = NULL;
     rrd->live_head = NULL;
+    rrd->legacy_last_up = NULL;
     rrd->rra_ptr = NULL;
     rrd->pdp_prep = NULL;
     rrd->cdp_prep = NULL;
@@ -521,9 +584,12 @@ void rrd_init(
 /* free RRD header data.  */
 
 #ifdef HAVE_MMAP
-inline void rrd_free(
-    rrd_t UNUSED(*rrd))
+void rrd_free(
+    rrd_t *rrd)
 {
+    if (rrd->legacy_last_up) {  /* this gets set for version < 3 only */
+        free(rrd->live_head);
+    }
 }
 #else
 void rrd_free(
@@ -549,64 +615,3 @@ void rrd_freemem(
 {
     free(mem);
 }
-
-
-/* XXX: FIXME: missing documentation.  */
-/*XXX: FIXME should be renamed to rrd_readfile or _rrd_readfile */
-
-int /*_rrd_*/ readfile(
-    const char *file_name,
-    char **buffer,
-    int skipfirst)
-{
-    long      writecnt = 0, totalcnt = MEMBLK;
-    long      offset = 0;
-    FILE     *input = NULL;
-    char      c;
-
-    if ((strcmp("-", file_name) == 0)) {
-        input = stdin;
-    } else {
-        if ((input = fopen(file_name, "rb")) == NULL) {
-            rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno));
-            return (-1);
-        }
-    }
-    if (skipfirst) {
-        do {
-            c = getc(input);
-            offset++;
-        } while (c != '\n' && !feof(input));
-    }
-    if (strcmp("-", file_name)) {
-        fseek(input, 0, SEEK_END);
-        /* have extra space for detecting EOF without realloc */
-        totalcnt = (ftell(input) + 1) / sizeof(char) - offset;
-        if (totalcnt < MEMBLK)
-            totalcnt = MEMBLK;  /* sanitize */
-        fseek(input, offset * sizeof(char), SEEK_SET);
-    }
-    if (((*buffer) = (char *) malloc((totalcnt + 4) * sizeof(char))) == NULL) {
-        perror("Allocate Buffer:");
-        exit(1);
-    };
-    do {
-        writecnt +=
-            fread((*buffer) + writecnt, 1,
-                  (totalcnt - writecnt) * sizeof(char), input);
-        if (writecnt >= totalcnt) {
-            totalcnt += MEMBLK;
-            if (((*buffer) =
-                 rrd_realloc((*buffer),
-                             (totalcnt + 4) * sizeof(char))) == NULL) {
-                perror("Realloc Buffer:");
-                exit(1);
-            };
-        }
-    } while (!feof(input));
-    (*buffer)[writecnt] = '\0';
-    if (strcmp("-", file_name) != 0) {
-        fclose(input);
-    };
-    return writecnt;
-}