tdb: make TDB_NOSYNC merely disable sync.
authorRusty Russell <rusty@rustcorp.com.au>
Fri, 22 Jun 2012 05:37:44 +0000 (15:07 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Fri, 22 Jun 2012 05:35:17 +0000 (07:35 +0200)
(As suggested by Stefan Metzmacher, based on the change to ntdb.)

Since commit ec96ea690edbe3398d690b4a953d487ca1773f1c, we handle the case
where a process dies during a transaction commit.  Unfortunately, TDB_NOSYNC
means this no longer works, as it disables the recovery area as well as the
actual msync/fsync.  We should do everything except the syncs.

This also means we can do a complete test with $TDB_NO_FSYNC set; just
to get more complete coverage, we disable it explicitly for one test
(where we override the actual sync calls anyway).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
lib/tdb/common/transaction.c
lib/tdb/test/run-transaction-expand.c
lib/tdb/wscript

index c3477eb80ca27385240a5afc2e60501d150d9767..f18b4c229eb8400275b90eae8ef2582ca3736767 100644 (file)
@@ -82,8 +82,9 @@
     intervention.
 
   - if TDB_NOSYNC is passed to flags in tdb_open then transactions are
-    still available, but no transaction recovery area is used and no
-    fsync/msync calls are made.
+    still available, but no fsync/msync calls are made.  This means we
+    are still proof against a process dying during transaction commit,
+    but not against machine reboot.
 
   - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using
     tdb_add_flags() transaction nesting is enabled.
@@ -976,13 +977,11 @@ static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
                return -1;
        }
 
-       if (!(tdb->flags & TDB_NOSYNC)) {
-               /* write the recovery data to the end of the file */
-               if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
-                       _tdb_transaction_cancel(tdb);
-                       return -1;
-               }
+       /* write the recovery data to the end of the file */
+       if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
+               _tdb_transaction_cancel(tdb);
+               return -1;
        }
 
        tdb->transaction->prepared = true;
index 3b79dbb6eaec3e46bf45b803b05879d355efd626..bc22d2b53e47e02cdb2579775f99e94864e0640e 100644 (file)
@@ -1,8 +1,10 @@
 #include "../common/tdb_private.h"
 
-/* Speed up the tests: setting TDB_NOSYNC removed recovery altogether. */
+/* Speed up the tests, but do the actual sync tests. */
+static unsigned int sync_counts = 0;
 static inline int fake_fsync(int fd)
 {
+       sync_counts++;
        return 0;
 }
 #define fsync fake_fsync
@@ -10,6 +12,7 @@ static inline int fake_fsync(int fd)
 #ifdef MS_SYNC
 static inline int fake_msync(void *addr, size_t length, int flags)
 {
+       sync_counts++;
        return 0;
 }
 #define msync fake_msync
@@ -18,6 +21,7 @@ static inline int fake_msync(void *addr, size_t length, int flags)
 #ifdef HAVE_FDATASYNC
 static inline int fake_fdatasync(int fd)
 {
+       sync_counts++;
        return 0;
 }
 #define fdatasync fake_fdatasync
@@ -59,7 +63,10 @@ int main(int argc, char *argv[])
        struct tdb_record rec;
        tdb_off_t off;
 
-       plan_tests(4);
+       /* Do *not* suppress sync for this test; we do it ourselves. */
+       unsetenv("TDB_NO_FSYNC");
+
+       plan_tests(5);
        tdb = tdb_open_ex("run-transaction-expand.tdb",
                          1024, TDB_CLEAR_IF_FIRST,
                          O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
@@ -103,6 +110,9 @@ int main(int argc, char *argv[])
 
        /* We should only be about 4 times larger than largest record. */
        ok1(tdb->map_size < 5 * i * getpagesize());
+
+       /* We should have synchronized multiple times. */
+       ok1(sync_counts);
        tdb_close(tdb);
        free(data.dptr);
 
index 01b4892fb02cd813b3a4548556be086340d0aef1..e28e43acac2ec99a7119237863da8c14f676399e 100644 (file)
@@ -185,10 +185,6 @@ def testonly(ctx):
         if not os.path.exists(link):
             os.symlink(os.path.abspath(os.path.join(env.cwd, 'test')), link)
 
-        # unset TDB_NO_FSYNC, since we want to test sync code.
-        if 'TDB_NO_FSYNC' in os.environ:
-            del os.environ['TDB_NO_FSYNC']
-
         for f in 'tdb1-run-3G-file', 'tdb1-run-bad-tdb-header', 'tdb1-run', 'tdb1-run-check', 'tdb1-run-corrupt', 'tdb1-run-die-during-transaction', 'tdb1-run-endian', 'tdb1-run-incompatible', 'tdb1-run-nested-transactions', 'tdb1-run-nested-traverse', 'tdb1-run-no-lock-during-traverse', 'tdb1-run-oldhash', 'tdb1-run-open-during-transaction', 'tdb1-run-readonly-check', 'tdb1-run-rwlock-check', 'tdb1-run-summary', 'tdb1-run-transaction-expand', 'tdb1-run-traverse-in-transaction', 'tdb1-run-wronghash-fail', 'tdb1-run-zero-append':
             cmd = "cd " + testdir + " && " + os.path.abspath(os.path.join(Utils.g_module.blddir, f)) + " > test-output 2>&1"
             print("..." + f)