Changeset: aa2e3065be7e for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=aa2e3065be7e
Modified Files:
        gdk/gdk_bbp.c
        gdk/gdk_heap.c
Branch: Feb2013
Log Message:

For memory mapped files, create a backup copy before widening.
This solves a problem that we don't control what's in the actual file
until the next commit happens, so a crash might otherwise leave the
file (and the database) in an inconsistent state.


diffs (118 lines):

diff --git a/gdk/gdk_bbp.c b/gdk/gdk_bbp.c
--- a/gdk/gdk_bbp.c
+++ b/gdk/gdk_bbp.c
@@ -3161,8 +3161,14 @@ do_backup(const char *srcdir, const char
        int ret = 0;
 
         /* direct mmap is unprotected (readonly usage, or has WAL
-         * protection)  */
-       if (h->storage != STORE_MMAP) {
+         * protection); however, if we're backing up for subcommit
+         * and a backup already exists in the main backup directory
+         * (see GDKupgradevarheap), move the file */
+       if (subcommit && file_exists(BAKDIR, nme, extbase)) {
+               assert(h->storage == STORE_MMAP);
+               if (file_move(BAKDIR, SUBDIR, nme, extbase))
+                       return -1;
+       } else if (h->storage != STORE_MMAP) {
                /* STORE_PRIV saves into X.new files. Two cases could
                 * happen. The first is when a valid X.new exists
                 * because of an access change or a previous
diff --git a/gdk/gdk_heap.c b/gdk/gdk_heap.c
--- a/gdk/gdk_heap.c
+++ b/gdk/gdk_heap.c
@@ -394,6 +394,20 @@ HEAPshrink(Heap *h, size_t size)
        return -1;
 }
 
+/* returns 1 if the file exists */
+static int
+file_exists(const char *dir, const char *name, const char *ext)
+{
+       long_str path;
+       struct stat st;
+       int ret;
+
+       GDKfilepath(path, dir, name, ext);
+       ret = stat(path, &st);
+       IODEBUG THRprintf(GDKstdout, "#stat(%s) = %d\n", path, ret);
+       return (ret == 0);
+}
+
 int
 GDKupgradevarheap(COLrec *c, var_t v, int copyall)
 {
@@ -407,6 +421,7 @@ GDKupgradevarheap(COLrec *c, var_t v, in
 #endif
        size_t i, n;
        size_t savefree;
+       const char *filename;
 
        assert(c->heap.parentid == 0);
        assert(width != 0);
@@ -418,11 +433,65 @@ GDKupgradevarheap(COLrec *c, var_t v, in
        }
        assert(c->width < width);
        assert(c->shift < shift);
+
        /* if copyall is set, we need to convert the whole heap, since
         * we may be in the middle of an insert loop that adjusts the
         * free value at the end; otherwise only copy the area
         * indicated by the "free" pointer */
        n = (copyall ? c->heap.size : c->heap.free) >> c->shift;
+
+       /* for memory mapped files, create a backup copy before widening
+        *
+        * this solves a problem that we don't control what's in the
+        * actual file until the next commit happens, so a crash might
+        * otherwise leave the file (and the database) in an
+        * inconsistent state
+        *
+        * also see do_backup in gdk_bbp.c */
+       filename = strrchr(c->heap.filename, DIR_SEP);
+       if (filename == NULL)
+               filename = c->heap.filename;
+       else
+               filename++;
+       if (c->heap.storage == STORE_MMAP && !file_exists(BAKDIR, filename, 
NULL)) {
+               int fd;
+               ssize_t ret = 0;
+               size_t size = n << c->shift;
+               const char *base = c->heap.base;
+
+               /* first save heap in file with extra .tmp extension */
+               if ((fd = GDKfdlocate(c->heap.filename, "wb", "tmp")) < 0)
+                       return GDK_FAIL;
+               while (size > 0) {
+                       ret = write(fd, base, (unsigned) MIN(1 << 30, size));
+                       if (ret < 0)
+                               size = 0;
+                       size -= ret;
+                       base += ret;
+               }
+               if (ret < 0 ||
+#if defined(NATIVE_WIN32)
+                   _commit(fd) < 0 ||
+#elif defined(HAVE_FDATASYNC)
+                   fdatasync(fd) < 0 ||
+#elif defined(HAVE_FSYNC)
+                   fsync(fd) < 0 ||
+#endif
+                   close(fd) < 0) {
+                       /* something went wrong: abandon ship */
+                       close(fd);
+                       GDKunlink(BATDIR, c->heap.filename, "tmp");
+                       return GDK_FAIL;
+               }
+               /* move tmp file to backup directory (without .tmp
+                * extension) */
+               if (GDKmove(BATDIR, c->heap.filename, "tmp", BAKDIR, filename, 
NULL) < 0) {
+                       /* backup failed */
+                       GDKunlink(BATDIR, c->heap.filename, "tmp");
+                       return GDK_FAIL;
+               }
+       }
+
        savefree = c->heap.free;
        if (copyall)
                c->heap.free = c->heap.size;
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to