tdb: test for readonly locks mode on tdbbackup command
[samba.git] / lib / tdb / tools / tdbtorture.c
index 79fe3cd5e0e9ba6dd9c95b882770b5f2fde37f43..3640dc7ed6cd592fcc21d1f3cb4d82d037c54b8c 100644 (file)
@@ -1,5 +1,5 @@
 /* this tests tdb by doing lots of ops from several simultaneous
-   writers - that stresses the locking code. 
+   writers - that stresses the locking code.
 */
 
 #include "replace.h"
@@ -33,6 +33,7 @@ static int always_transaction = 0;
 static int hash_size = 2;
 static int loopnum;
 static int count_pipe;
+static bool mutex = false;
 static struct tdb_logging_context log_ctx;
 
 #ifdef PRINTF_ATTRIBUTE
@@ -59,7 +60,7 @@ static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const c
                system(ptr);
                free(ptr);
        }
-#endif 
+#endif
 }
 
 static void fatal(const char *why)
@@ -216,21 +217,31 @@ static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
 
 static void usage(void)
 {
-       printf("Usage: tdbtorture [-t] [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
+       printf("Usage: tdbtorture [-t] [-k] [-m] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
        exit(0);
 }
 
 static void send_count_and_suicide(int sig)
 {
+       ssize_t ret;
+
        /* This ensures our successor can continue where we left off. */
-       write(count_pipe, &loopnum, sizeof(loopnum));
+       do {
+               ret = write(count_pipe, &loopnum, sizeof(loopnum));
+       } while (ret == -1 && errno == EINTR);
        /* This gives a unique signature. */
        kill(getpid(), SIGUSR2);
 }
 
-static int run_child(int i, int seed, unsigned num_loops, unsigned start)
+static int run_child(const char *filename, int i, int seed, unsigned num_loops, unsigned start)
 {
-       db = tdb_open_ex("torture.tdb", hash_size, TDB_DEFAULT,
+       int tdb_flags = TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH;
+
+       if (mutex) {
+               tdb_flags |= TDB_MUTEX_LOCKING;
+       }
+
+       db = tdb_open_ex(filename, hash_size, tdb_flags,
                         O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
        if (!db) {
                fatal("db open failed");
@@ -270,6 +281,24 @@ static int run_child(int i, int seed, unsigned num_loops, unsigned start)
        return (error_count < 100 ? error_count : 100);
 }
 
+static char *test_path(const char *filename)
+{
+       const char *prefix = getenv("TEST_DATA_PREFIX");
+
+       if (prefix) {
+               char *path = NULL;
+               int ret;
+
+               ret = asprintf(&path, "%s/%s", prefix, filename);
+               if (ret == -1) {
+                       return NULL;
+               }
+               return path;
+       }
+
+       return strdup(filename);
+}
+
 int main(int argc, char * const *argv)
 {
        int i, seed = -1;
@@ -280,10 +309,11 @@ int main(int argc, char * const *argv)
        pid_t *pids;
        int kill_random = 0;
        int *done;
+       char *test_tdb;
 
        log_ctx.log_fn = tdb_log;
 
-       while ((c = getopt(argc, argv, "n:l:s:H:thk")) != -1) {
+       while ((c = getopt(argc, argv, "n:l:s:H:thkm")) != -1) {
                switch (c) {
                case 'n':
                        num_procs = strtol(optarg, NULL, 0);
@@ -303,25 +333,46 @@ int main(int argc, char * const *argv)
                case 'k':
                        kill_random = 1;
                        break;
+               case 'm':
+                       mutex = tdb_runtime_check_for_robust_mutexes();
+                       if (!mutex) {
+                               printf("tdb_runtime_check_for_robust_mutexes() returned false\n");
+                               exit(1);
+                       }
+                       break;
                default:
                        usage();
                }
        }
 
-       unlink("torture.tdb");
+       test_tdb = test_path("torture.tdb");
+
+       unlink(test_tdb);
 
        if (seed == -1) {
                seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
        }
 
+       printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
+              num_procs, num_loops, hash_size, seed,
+              (always_transaction ? " (all within transactions)" : ""));
+
        if (num_procs == 1 && !kill_random) {
                /* Don't fork for this case, makes debugging easier. */
-               error_count = run_child(0, seed, num_loops, 0);
+               error_count = run_child(test_tdb, 0, seed, num_loops, 0);
                goto done;
        }
 
        pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
+       if (pids == NULL) {
+               perror("Unable to allocate memory for pids");
+               exit(1);
+       }
        done = (int *)calloc(sizeof(int), num_procs);
+       if (done == NULL) {
+               perror("Unable to allocate memory for done");
+               exit(1);
+       }
 
        if (pipe(pfds) != 0) {
                perror("Creating pipe");
@@ -332,11 +383,7 @@ int main(int argc, char * const *argv)
        for (i=0;i<num_procs;i++) {
                if ((pids[i]=fork()) == 0) {
                        close(pfds[0]);
-                       if (i == 0) {
-                               printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
-                                      num_procs, num_loops, hash_size, seed, always_transaction ? " (all within transactions)" : "");
-                       }
-                       exit(run_child(i, seed, num_loops, 0));
+                       exit(run_child(test_tdb, i, seed, num_loops, 0));
                }
        }
 
@@ -384,13 +431,17 @@ int main(int argc, char * const *argv)
                            || WTERMSIG(status) == SIGUSR1) {
                                /* SIGUSR2 means they wrote to pipe. */
                                if (WTERMSIG(status) == SIGUSR2) {
-                                       read(pfds[0], &done[j],
-                                            sizeof(done[j]));
+                                       ssize_t ret;
+
+                                       do {
+                                               ret = read(pfds[0], &done[j],
+                                                          sizeof(done[j]));
+                                       } while (ret == -1 && errno == EINTR);
                                }
                                pids[j] = fork();
                                if (pids[j] == 0)
-                                       exit(run_child(j, seed, num_loops,
-                                                      done[j]));
+                                       exit(run_child(test_tdb, j, seed,
+                                                      num_loops, done[j]));
                                printf("Restarting child %i for %u-%u\n",
                                       j, done[j], num_loops);
                                continue;
@@ -414,18 +465,26 @@ int main(int argc, char * const *argv)
 
 done:
        if (error_count == 0) {
-               db = tdb_open_ex("torture.tdb", hash_size, TDB_DEFAULT,
+               int tdb_flags = TDB_DEFAULT;
+
+               if (mutex) {
+                       tdb_flags |= TDB_NOLOCK;
+               }
+
+               db = tdb_open_ex(test_tdb, hash_size, tdb_flags,
                                 O_RDWR, 0, &log_ctx, NULL);
                if (!db) {
-                       fatal("db open failed");
+                       fatal("db open failed\n");
+                       exit(1);
                }
                if (tdb_check(db, NULL, NULL) == -1) {
-                       printf("db check failed");
+                       printf("db check failed\n");
                        exit(1);
                }
                tdb_close(db);
                printf("OK\n");
        }
 
+       free(test_tdb);
        return error_count;
 }