]> git.ozlabs.org Git - ccan/commitdiff
tdb2: rename the tools to tdb2torture, tdb2tool and mktdb2
authorRusty Russell <rusty@rustcorp.com.au>
Fri, 17 Jun 2011 05:11:55 +0000 (14:41 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Fri, 17 Jun 2011 05:11:55 +0000 (14:41 +0930)
This means they can be installed in parallel with tdb1's tools.

ccan/tdb2/tools/Makefile
ccan/tdb2/tools/mktdb.c [deleted file]
ccan/tdb2/tools/mktdb2.c [new file with mode: 0644]
ccan/tdb2/tools/tdb2tool.c [new file with mode: 0644]
ccan/tdb2/tools/tdb2torture.c [new file with mode: 0644]
ccan/tdb2/tools/tdbtool.c [deleted file]
ccan/tdb2/tools/tdbtorture.c [deleted file]

index e2ad888390a79d9e69cc84eda902055fcd494517..d388e51b555e63d041dda9475bd4f94d5b51f90d 100644 (file)
@@ -2,13 +2,13 @@ OBJS:=../../tdb2.o ../../hash.o ../../tally.o
 CFLAGS:=-I../../.. -Wall -g -O3 #-g -pg
 LDFLAGS:=-L../../..
 
 CFLAGS:=-I../../.. -Wall -g -O3 #-g -pg
 LDFLAGS:=-L../../..
 
-default: tdbtorture tdbtool mktdb speed growtdb-bench
+default: tdb2torture tdb2tool mktdb2 speed growtdb-bench
 
 
-tdbtorture: tdbtorture.c $(OBJS)
-tdbtool: tdbtool.c $(OBJS)
-mktdb: mktdb.c $(OBJS)
+tdb2torture: tdb2torture.c $(OBJS)
+tdb2tool: tdb2tool.c $(OBJS)
+mktdb2: mktdb2.c $(OBJS)
 speed: speed.c $(OBJS)
 growtdb-bench: growtdb-bench.c $(OBJS)
 
 clean:
 speed: speed.c $(OBJS)
 growtdb-bench: growtdb-bench.c $(OBJS)
 
 clean:
-       rm -f tdbtorture tdbtool mktdb speed growtdb-bench
+       rm -f tdb2torture tdb2tool mktdb2 speed growtdb-bench
diff --git a/ccan/tdb2/tools/mktdb.c b/ccan/tdb2/tools/mktdb.c
deleted file mode 100644 (file)
index 79011b1..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <ccan/tdb2/tdb2.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <err.h>
-
-int main(int argc, char *argv[])
-{
-       unsigned int i, num_recs;
-       struct tdb_context *tdb;
-
-       if (argc != 3 || (num_recs = atoi(argv[2])) == 0)
-               errx(1, "Usage: mktdb <tdbfile> <numrecords>");
-
-       tdb = tdb_open(argv[1], TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR, 0600,NULL);
-       if (!tdb)
-               err(1, "Opening %s", argv[1]);
-
-       for (i = 0; i < num_recs; i++) {
-               TDB_DATA d;
-
-               d.dptr = (void *)&i;
-               d.dsize = sizeof(i);
-               if (tdb_store(tdb, d, d, TDB_INSERT) != 0)
-                       err(1, "Failed to store record %i", i);
-       }
-       printf("Done\n");
-       return 0;
-}
diff --git a/ccan/tdb2/tools/mktdb2.c b/ccan/tdb2/tools/mktdb2.c
new file mode 100644 (file)
index 0000000..79011b1
--- /dev/null
@@ -0,0 +1,29 @@
+#include <ccan/tdb2/tdb2.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <err.h>
+
+int main(int argc, char *argv[])
+{
+       unsigned int i, num_recs;
+       struct tdb_context *tdb;
+
+       if (argc != 3 || (num_recs = atoi(argv[2])) == 0)
+               errx(1, "Usage: mktdb <tdbfile> <numrecords>");
+
+       tdb = tdb_open(argv[1], TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR, 0600,NULL);
+       if (!tdb)
+               err(1, "Opening %s", argv[1]);
+
+       for (i = 0; i < num_recs; i++) {
+               TDB_DATA d;
+
+               d.dptr = (void *)&i;
+               d.dsize = sizeof(i);
+               if (tdb_store(tdb, d, d, TDB_INSERT) != 0)
+                       err(1, "Failed to store record %i", i);
+       }
+       printf("Done\n");
+       return 0;
+}
diff --git a/ccan/tdb2/tools/tdb2tool.c b/ccan/tdb2/tools/tdb2tool.c
new file mode 100644 (file)
index 0000000..262253c
--- /dev/null
@@ -0,0 +1,798 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba database functions
+   Copyright (C) Andrew Tridgell              1999-2000
+   Copyright (C) Paul `Rusty' Russell             2000
+   Copyright (C) Jeremy Allison                           2000
+   Copyright (C) Andrew Esh                        2001
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <ccan/tdb2/tdb2.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+static int do_command(void);
+const char *cmdname;
+char *arg1, *arg2;
+size_t arg1len, arg2len;
+int bIterate = 0;
+char *line;
+TDB_DATA iterate_kbuf;
+char cmdline[1024];
+static int disable_mmap;
+
+enum commands {
+       CMD_CREATE_TDB,
+       CMD_OPEN_TDB,
+       CMD_TRANSACTION_START,
+       CMD_TRANSACTION_COMMIT,
+       CMD_TRANSACTION_CANCEL,
+       CMD_ERASE,
+       CMD_DUMP,
+       CMD_INSERT,
+       CMD_MOVE,
+       CMD_STORE,
+       CMD_SHOW,
+       CMD_KEYS,
+       CMD_HEXKEYS,
+       CMD_DELETE,
+#if 0
+       CMD_LIST_HASH_FREE,
+       CMD_LIST_FREE,
+#endif
+       CMD_INFO,
+       CMD_MMAP,
+       CMD_SPEED,
+       CMD_FIRST,
+       CMD_NEXT,
+       CMD_SYSTEM,
+       CMD_CHECK,
+       CMD_QUIT,
+       CMD_HELP
+};
+
+typedef struct {
+       const char *name;
+       enum commands cmd;
+} COMMAND_TABLE;
+
+COMMAND_TABLE cmd_table[] = {
+       {"create",      CMD_CREATE_TDB},
+       {"open",        CMD_OPEN_TDB},
+#if 0
+       {"transaction_start",   CMD_TRANSACTION_START},
+       {"transaction_commit",  CMD_TRANSACTION_COMMIT},
+       {"transaction_cancel",  CMD_TRANSACTION_CANCEL},
+#endif
+       {"erase",       CMD_ERASE},
+       {"dump",        CMD_DUMP},
+       {"insert",      CMD_INSERT},
+       {"move",        CMD_MOVE},
+       {"store",       CMD_STORE},
+       {"show",        CMD_SHOW},
+       {"keys",        CMD_KEYS},
+       {"hexkeys",     CMD_HEXKEYS},
+       {"delete",      CMD_DELETE},
+#if 0
+       {"list",        CMD_LIST_HASH_FREE},
+       {"free",        CMD_LIST_FREE},
+#endif
+       {"info",        CMD_INFO},
+       {"speed",       CMD_SPEED},
+       {"mmap",        CMD_MMAP},
+       {"first",       CMD_FIRST},
+       {"1",           CMD_FIRST},
+       {"next",        CMD_NEXT},
+       {"n",           CMD_NEXT},
+       {"check",       CMD_CHECK},
+       {"quit",        CMD_QUIT},
+       {"q",           CMD_QUIT},
+       {"!",           CMD_SYSTEM},
+       {NULL,          CMD_HELP}
+};
+
+struct timeval tp1,tp2;
+
+static void _start_timer(void)
+{
+       gettimeofday(&tp1,NULL);
+}
+
+static double _end_timer(void)
+{
+       gettimeofday(&tp2,NULL);
+       return((tp2.tv_sec - tp1.tv_sec) + 
+              (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
+                   const char *message, void *priv)
+{
+       fputs(message, stderr);
+}
+
+/* a tdb tool for manipulating a tdb database */
+
+static struct tdb_context *tdb;
+
+static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
+
+static void print_asc(const char *buf,int len)
+{
+       int i;
+
+       /* We're probably printing ASCII strings so don't try to display
+          the trailing NULL character. */
+
+       if (buf[len - 1] == 0)
+               len--;
+
+       for (i=0;i<len;i++)
+               printf("%c",isprint(buf[i])?buf[i]:'.');
+}
+
+static void print_data(const char *buf,int len)
+{
+       int i=0;
+       if (len<=0) return;
+       printf("[%03X] ",i);
+       for (i=0;i<len;) {
+               printf("%02X ",(int)((unsigned char)buf[i]));
+               i++;
+               if (i%8 == 0) printf(" ");
+               if (i%16 == 0) {      
+                       print_asc(&buf[i-16],8); printf(" ");
+                       print_asc(&buf[i-8],8); printf("\n");
+                       if (i<len) printf("[%03X] ",i);
+               }
+       }
+       if (i%16) {
+               int n;
+               
+               n = 16 - (i%16);
+               printf(" ");
+               if (n>8) printf(" ");
+               while (n--) printf("   ");
+               
+               n = i%16;
+               if (n > 8) n = 8;
+               print_asc(&buf[i-(i%16)],n); printf(" ");
+               n = (i%16) - n;
+               if (n>0) print_asc(&buf[i-n],n); 
+               printf("\n");    
+       }
+}
+
+static void help(void)
+{
+       printf("\n"
+"tdbtool: \n"
+"  create    dbname     : create a database\n"
+"  open      dbname     : open an existing database\n"
+"  openjh    dbname     : open an existing database (jenkins hash)\n"
+"  transaction_start    : start a transaction\n"
+"  transaction_commit   : commit a transaction\n"
+"  transaction_cancel   : cancel a transaction\n"
+"  erase                : erase the database\n"
+"  dump                 : dump the database as strings\n"
+"  keys                 : dump the database keys as strings\n"
+"  hexkeys              : dump the database keys as hex values\n"
+"  info                 : print summary info about the database\n"
+"  insert    key  data  : insert a record\n"
+"  move      key  file  : move a record to a destination tdb\n"
+"  store     key  data  : store a record (replace)\n"
+"  show      key        : show a record by key\n"
+"  delete    key        : delete a record by key\n"
+#if 0
+"  list                 : print the database hash table and freelist\n"
+"  free                 : print the database freelist\n"
+#endif
+"  check                : check the integrity of an opened database\n"
+"  speed                : perform speed tests on the database\n"
+"  ! command            : execute system command\n"
+"  1 | first            : print the first record\n"
+"  n | next             : print the next record\n"
+"  q | quit             : terminate\n"
+"  \\n                   : repeat 'next' command\n"
+"\n");
+}
+
+static void terror(enum TDB_ERROR err, const char *why)
+{
+       if (err != TDB_SUCCESS)
+               printf("%s:%s\n", tdb_errorstr(err), why);
+       else
+               printf("%s\n", why);
+}
+
+static void create_tdb(const char *tdbname)
+{
+       union tdb_attribute log_attr;
+       log_attr.base.attr = TDB_ATTRIBUTE_LOG;
+       log_attr.base.next = NULL;
+       log_attr.log.fn = tdb_log;
+
+       if (tdb) tdb_close(tdb);
+       tdb = tdb_open(tdbname, (disable_mmap?TDB_NOMMAP:0),
+                      O_RDWR | O_CREAT | O_TRUNC, 0600, &log_attr);
+       if (!tdb) {
+               printf("Could not create %s: %s\n", tdbname, strerror(errno));
+       }
+}
+
+static void open_tdb(const char *tdbname)
+{
+       union tdb_attribute log_attr;
+       log_attr.base.attr = TDB_ATTRIBUTE_LOG;
+       log_attr.base.next = NULL;
+       log_attr.log.fn = tdb_log;
+
+       if (tdb) tdb_close(tdb);
+       tdb = tdb_open(tdbname, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
+                      &log_attr);
+       if (!tdb) {
+               printf("Could not open %s: %s\n", tdbname, strerror(errno));
+       }
+}
+
+static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+       TDB_DATA key, dbuf;
+       enum TDB_ERROR ecode;
+
+       if ((keyname == NULL) || (keylen == 0)) {
+               terror(TDB_SUCCESS, "need key");
+               return;
+       }
+
+       key.dptr = (unsigned char *)keyname;
+       key.dsize = keylen;
+       dbuf.dptr = (unsigned char *)data;
+       dbuf.dsize = datalen;
+
+       ecode = tdb_store(tdb, key, dbuf, TDB_INSERT);
+       if (ecode) {
+               terror(ecode, "insert failed");
+       }
+}
+
+static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
+{
+       TDB_DATA key, dbuf;
+       enum TDB_ERROR ecode;
+
+       if ((keyname == NULL) || (keylen == 0)) {
+               terror(TDB_SUCCESS, "need key");
+               return;
+       }
+
+       if ((data == NULL) || (datalen == 0)) {
+               terror(TDB_SUCCESS, "need data");
+               return;
+       }
+
+       key.dptr = (unsigned char *)keyname;
+       key.dsize = keylen;
+       dbuf.dptr = (unsigned char *)data;
+       dbuf.dsize = datalen;
+
+       printf("Storing key:\n");
+       print_rec(tdb, key, dbuf, NULL);
+
+       ecode = tdb_store(tdb, key, dbuf, TDB_REPLACE);
+       if (ecode) {
+               terror(ecode, "store failed");
+       }
+}
+
+static void show_tdb(char *keyname, size_t keylen)
+{
+       TDB_DATA key, dbuf;
+       enum TDB_ERROR ecode;
+
+       if ((keyname == NULL) || (keylen == 0)) {
+               terror(TDB_SUCCESS, "need key");
+               return;
+       }
+
+       key.dptr = (unsigned char *)keyname;
+       key.dsize = keylen;
+
+       ecode = tdb_fetch(tdb, key, &dbuf);
+       if (ecode) {
+               terror(ecode, "fetch failed");
+               return;
+       }
+       
+       print_rec(tdb, key, dbuf, NULL);
+       
+       free( dbuf.dptr );
+}
+
+static void delete_tdb(char *keyname, size_t keylen)
+{
+       TDB_DATA key;
+       enum TDB_ERROR ecode;
+
+       if ((keyname == NULL) || (keylen == 0)) {
+               terror(TDB_SUCCESS, "need key");
+               return;
+       }
+
+       key.dptr = (unsigned char *)keyname;
+       key.dsize = keylen;
+
+       ecode = tdb_delete(tdb, key);
+       if (ecode) {
+               terror(ecode, "delete failed");
+       }
+}
+
+static void move_rec(char *keyname, size_t keylen, char* tdbname)
+{
+       TDB_DATA key, dbuf;
+       struct tdb_context *dst_tdb;
+       enum TDB_ERROR ecode;
+
+       if ((keyname == NULL) || (keylen == 0)) {
+               terror(TDB_SUCCESS, "need key");
+               return;
+       }
+
+       if ( !tdbname ) {
+               terror(TDB_SUCCESS, "need destination tdb name");
+               return;
+       }
+
+       key.dptr = (unsigned char *)keyname;
+       key.dsize = keylen;
+
+       ecode = tdb_fetch(tdb, key, &dbuf);
+       if (ecode) {
+               terror(ecode, "fetch failed");
+               return;
+       }
+       
+       print_rec(tdb, key, dbuf, NULL);
+       
+       dst_tdb = tdb_open(tdbname, 0, O_RDWR, 0600, NULL);
+       if ( !dst_tdb ) {
+               terror(TDB_SUCCESS, "unable to open destination tdb");
+               return;
+       }
+       
+       ecode = tdb_store( dst_tdb, key, dbuf, TDB_REPLACE);
+       if (ecode)
+               terror(ecode, "failed to move record");
+       else
+               printf("record moved\n");
+       
+       tdb_close( dst_tdb );
+}
+
+static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+       printf("\nkey %d bytes\n", (int)key.dsize);
+       print_asc((const char *)key.dptr, key.dsize);
+       printf("\ndata %d bytes\n", (int)dbuf.dsize);
+       print_data((const char *)dbuf.dptr, dbuf.dsize);
+       return 0;
+}
+
+static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+       printf("key %d bytes: ", (int)key.dsize);
+       print_asc((const char *)key.dptr, key.dsize);
+       printf("\n");
+       return 0;
+}
+
+static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+       printf("key %d bytes\n", (int)key.dsize);
+       print_data((const char *)key.dptr, key.dsize);
+       printf("\n");
+       return 0;
+}
+
+static int total_bytes;
+
+static int traverse_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+       total_bytes += dbuf.dsize;
+       return 0;
+}
+
+static void info_tdb(void)
+{
+       enum TDB_ERROR ecode;
+       char *summary;
+
+       ecode = tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &summary);
+
+       if (ecode) {
+               terror(ecode, "Getting summary");
+       } else {
+               printf("%s", summary);
+               free(summary);
+       }
+}
+
+static void speed_tdb(const char *tlimit)
+{
+       unsigned timelimit = tlimit?atoi(tlimit):0;
+       double t;
+       int ops;
+       if (timelimit == 0) timelimit = 5;
+
+       ops = 0;
+       printf("Testing store speed for %u seconds\n", timelimit);
+       _start_timer();
+       do {
+               long int r = random();
+               TDB_DATA key, dbuf;
+               key = tdb_mkdata("store test", strlen("store test"));
+               dbuf.dptr = (unsigned char *)&r;
+               dbuf.dsize = sizeof(r);
+               tdb_store(tdb, key, dbuf, TDB_REPLACE);
+               t = _end_timer();
+               ops++;
+       } while (t < timelimit);
+       printf("%10.3f ops/sec\n", ops/t);
+
+       ops = 0;
+       printf("Testing fetch speed for %u seconds\n", timelimit);
+       _start_timer();
+       do {
+               long int r = random();
+               TDB_DATA key, dbuf;
+               key = tdb_mkdata("store test", strlen("store test"));
+               dbuf.dptr = (unsigned char *)&r;
+               dbuf.dsize = sizeof(r);
+               tdb_fetch(tdb, key, &dbuf);
+               t = _end_timer();
+               ops++;
+       } while (t < timelimit);
+       printf("%10.3f ops/sec\n", ops/t);
+
+       ops = 0;
+       printf("Testing transaction speed for %u seconds\n", timelimit);
+       _start_timer();
+       do {
+               long int r = random();
+               TDB_DATA key, dbuf;
+               key = tdb_mkdata("transaction test", strlen("transaction test"));
+               dbuf.dptr = (unsigned char *)&r;
+               dbuf.dsize = sizeof(r);
+               tdb_transaction_start(tdb);
+               tdb_store(tdb, key, dbuf, TDB_REPLACE);
+               tdb_transaction_commit(tdb);
+               t = _end_timer();
+               ops++;
+       } while (t < timelimit);
+       printf("%10.3f ops/sec\n", ops/t);
+
+       ops = 0;
+       printf("Testing traverse speed for %u seconds\n", timelimit);
+       _start_timer();
+       do {
+               tdb_traverse(tdb, traverse_fn, NULL);
+               t = _end_timer();
+               ops++;
+       } while (t < timelimit);
+       printf("%10.3f ops/sec\n", ops/t);
+}
+
+static void toggle_mmap(void)
+{
+       disable_mmap = !disable_mmap;
+       if (disable_mmap) {
+               printf("mmap is disabled\n");
+       } else {
+               printf("mmap is enabled\n");
+       }
+}
+
+static char *tdb_getline(const char *prompt)
+{
+       static char thisline[1024];
+       char *p;
+       fputs(prompt, stdout);
+       thisline[0] = 0;
+       p = fgets(thisline, sizeof(thisline)-1, stdin);
+       if (p) p = strchr(p, '\n');
+       if (p) *p = 0;
+       return p?thisline:NULL;
+}
+
+static int do_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
+                     void *state)
+{
+    return tdb_delete(the_tdb, key);
+}
+
+static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
+{
+       TDB_DATA dbuf;
+       enum TDB_ERROR ecode;
+       ecode = tdb_firstkey(the_tdb, pkey);
+       if (!ecode)
+               ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
+       if (ecode) terror(ecode, "fetch failed");
+       else {
+               print_rec(the_tdb, *pkey, dbuf, NULL);
+       }
+}
+
+static void next_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
+{
+       TDB_DATA dbuf;
+       enum TDB_ERROR ecode;
+       ecode = tdb_nextkey(the_tdb, pkey);
+
+       if (!ecode)
+               ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
+       if (ecode) 
+               terror(ecode, "fetch failed");
+       else
+               print_rec(the_tdb, *pkey, dbuf, NULL);
+}
+
+static void check_db(struct tdb_context *the_tdb)
+{
+       if (!the_tdb) {
+               printf("Error: No database opened!\n");
+       } else {
+               if (tdb_check(the_tdb, NULL, NULL) != 0)
+                       printf("Integrity check for the opened database failed.\n");
+               else
+                       printf("Database integrity is OK.\n");
+       }
+}
+
+static int do_command(void)
+{
+       COMMAND_TABLE *ctp = cmd_table;
+       enum commands mycmd = CMD_HELP;
+       int cmd_len;
+
+       if (cmdname && strlen(cmdname) == 0) {
+               mycmd = CMD_NEXT;
+       } else {
+               while (ctp->name) {
+                       cmd_len = strlen(ctp->name);
+                       if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
+                               mycmd = ctp->cmd;
+                               break;
+                       }
+                       ctp++;
+               }
+       }
+
+       switch (mycmd) {
+       case CMD_CREATE_TDB:
+               bIterate = 0;
+               create_tdb(arg1);
+               return 0;
+       case CMD_OPEN_TDB:
+               bIterate = 0;
+               open_tdb(arg1);
+               return 0;
+       case CMD_SYSTEM:
+               /* Shell command */
+               if (system(arg1) == -1) {
+                       terror(TDB_SUCCESS, "system() call failed\n");
+               }
+               return 0;
+       case CMD_QUIT:
+               return 1;
+       default:
+               /* all the rest require a open database */
+               if (!tdb) {
+                       bIterate = 0;
+                       terror(TDB_SUCCESS, "database not open");
+                       help();
+                       return 0;
+               }
+               switch (mycmd) {
+               case CMD_TRANSACTION_START:
+                       bIterate = 0;
+                       tdb_transaction_start(tdb);
+                       return 0;
+               case CMD_TRANSACTION_COMMIT:
+                       bIterate = 0;
+                       tdb_transaction_commit(tdb);
+                       return 0;
+               case CMD_TRANSACTION_CANCEL:
+                       bIterate = 0;
+                       tdb_transaction_cancel(tdb);
+                       return 0;
+               case CMD_ERASE:
+                       bIterate = 0;
+                       tdb_traverse(tdb, do_delete_fn, NULL);
+                       return 0;
+               case CMD_DUMP:
+                       bIterate = 0;
+                       tdb_traverse(tdb, print_rec, NULL);
+                       return 0;
+               case CMD_INSERT:
+                       bIterate = 0;
+                       insert_tdb(arg1, arg1len,arg2,arg2len);
+                       return 0;
+               case CMD_MOVE:
+                       bIterate = 0;
+                       move_rec(arg1,arg1len,arg2);
+                       return 0;
+               case CMD_STORE:
+                       bIterate = 0;
+                       store_tdb(arg1,arg1len,arg2,arg2len);
+                       return 0;
+               case CMD_SHOW:
+                       bIterate = 0;
+                       show_tdb(arg1, arg1len);
+                       return 0;
+               case CMD_KEYS:
+                       tdb_traverse(tdb, print_key, NULL);
+                       return 0;
+               case CMD_HEXKEYS:
+                       tdb_traverse(tdb, print_hexkey, NULL);
+                       return 0;
+               case CMD_DELETE:
+                       bIterate = 0;
+                       delete_tdb(arg1,arg1len);
+                       return 0;
+#if 0
+               case CMD_LIST_HASH_FREE:
+                       tdb_dump_all(tdb);
+                       return 0;
+               case CMD_LIST_FREE:
+                       tdb_printfreelist(tdb);
+                       return 0;
+#endif
+               case CMD_INFO:
+                       info_tdb();
+                       return 0;
+               case CMD_SPEED:
+                       speed_tdb(arg1);
+                       return 0;
+               case CMD_MMAP:
+                       toggle_mmap();
+                       return 0;
+               case CMD_FIRST:
+                       bIterate = 1;
+                       first_record(tdb, &iterate_kbuf);
+                       return 0;
+               case CMD_NEXT:
+                       if (bIterate)
+                               next_record(tdb, &iterate_kbuf);
+                       return 0;
+               case CMD_CHECK:
+                       check_db(tdb);
+                       return 0;
+               case CMD_HELP:
+                       help();
+                       return 0;
+               case CMD_CREATE_TDB:
+               case CMD_OPEN_TDB:
+               case CMD_SYSTEM:
+               case CMD_QUIT:
+                       /*
+                        * unhandled commands.  cases included here to avoid compiler
+                        * warnings.
+                        */
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
+static char *convert_string(char *instring, size_t *sizep)
+{
+       size_t length = 0;
+       char *outp, *inp;
+       char temp[3];
+
+       outp = inp = instring;
+
+       while (*inp) {
+               if (*inp == '\\') {
+                       inp++;
+                       if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+                               temp[0] = *inp++;
+                               temp[1] = '\0';
+                               if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
+                                       temp[1] = *inp++;
+                                       temp[2] = '\0';
+                               }
+                               *outp++ = (char)strtol((const char *)temp,NULL,16);
+                       } else {
+                               *outp++ = *inp++;
+                       }
+               } else {
+                       *outp++ = *inp++;
+               }
+               length++;
+       }
+       *sizep = length;
+       return instring;
+}
+
+int main(int argc, char *argv[])
+{
+       cmdname = "";
+       arg1 = NULL;
+       arg1len = 0;
+       arg2 = NULL;
+       arg2len = 0;
+
+       if (argv[1]) {
+               cmdname = "open";
+               arg1 = argv[1];
+               do_command();
+               cmdname =  "";
+               arg1 = NULL;
+       }
+
+       switch (argc) {
+       case 1:
+       case 2:
+               /* Interactive mode */
+               while ((cmdname = tdb_getline("tdb> "))) {
+                       arg2 = arg1 = NULL;
+                       if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
+                               arg1++;
+                               arg2 = arg1;
+                               while (*arg2) {
+                                       if (*arg2 == ' ') {
+                                               *arg2++ = '\0';
+                                               break;
+                                       }
+                                       if ((*arg2++ == '\\') && (*arg2 == ' ')) {
+                                               arg2++;
+                                       }
+                               }
+                       }
+                       if (arg1) arg1 = convert_string(arg1,&arg1len);
+                       if (arg2) arg2 = convert_string(arg2,&arg2len);
+                       if (do_command()) break;
+               }
+               break;
+       case 5:
+               arg2 = convert_string(argv[4],&arg2len);
+       case 4:
+               arg1 = convert_string(argv[3],&arg1len);
+       case 3:
+               cmdname = argv[2];
+       default:
+               do_command();
+               break;
+       }
+
+       if (tdb) tdb_close(tdb);
+
+       return 0;
+}
diff --git a/ccan/tdb2/tools/tdb2torture.c b/ccan/tdb2/tools/tdb2torture.c
new file mode 100644 (file)
index 0000000..32d7ea3
--- /dev/null
@@ -0,0 +1,494 @@
+/* this tests tdb by doing lots of ops from several simultaneous
+   writers - that stresses the locking code. 
+*/
+
+#include <ccan/tdb2/tdb2.h>
+#include <stdlib.h>
+#include <err.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/wait.h>
+
+//#define REOPEN_PROB 30
+#define DELETE_PROB 8
+#define STORE_PROB 4
+#define APPEND_PROB 6
+#define TRANSACTION_PROB 10
+#define TRANSACTION_PREPARE_PROB 2
+#define LOCKSTORE_PROB 5
+#define TRAVERSE_PROB 20
+#define TRAVERSE_MOD_PROB 100
+#define TRAVERSE_ABORT_PROB 500
+#define CULL_PROB 100
+#define KEYLEN 3
+#define DATALEN 100
+
+static struct tdb_context *db;
+static int in_transaction;
+static int in_traverse;
+static int error_count;
+#if TRANSACTION_PROB
+static int always_transaction = 0;
+#endif
+static int loopnum;
+static int count_pipe;
+static union tdb_attribute log_attr;
+static union tdb_attribute seed_attr;
+
+static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
+                   const char *message, void *data)
+{
+       fputs(message, stdout);
+       fflush(stdout);
+#if 0
+       {
+               char str[200];
+               signal(SIGUSR1, SIG_IGN);
+               sprintf(str,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
+               system(str);
+       }
+#endif 
+}
+
+#include "../private.h"
+
+static void segv_handler(int sig, siginfo_t *info, void *p)
+{
+       char string[100];
+
+       sprintf(string, "%u: death at %p (map_ptr %p, map_size %zu)\n",
+               getpid(), info->si_addr, db->file->map_ptr,
+               (size_t)db->file->map_size);
+       if (write(2, string, strlen(string)) > 0)
+               sleep(60);
+       _exit(11);
+}      
+
+static void fatal(struct tdb_context *tdb, const char *why)
+{
+       fprintf(stderr, "%u:%s:%s\n", getpid(), why,
+               tdb ? tdb_errorstr(tdb_error(tdb)) : "(no tdb)");
+       error_count++;
+}
+
+static char *randbuf(int len)
+{
+       char *buf;
+       int i;
+       buf = (char *)malloc(len+1);
+
+       for (i=0;i<len;i++) {
+               buf[i] = 'a' + (rand() % 26);
+       }
+       buf[i] = 0;
+       return buf;
+}
+
+static void addrec_db(void);
+static int modify_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+                          void *state)
+{
+#if CULL_PROB
+       if (random() % CULL_PROB == 0) {
+               tdb_delete(tdb, key);
+       }
+#endif
+
+#if TRAVERSE_MOD_PROB
+       if (random() % TRAVERSE_MOD_PROB == 0) {
+               addrec_db();
+       }
+#endif
+
+#if TRAVERSE_ABORT_PROB
+       if (random() % TRAVERSE_ABORT_PROB == 0)
+               return 1;
+#endif
+
+       return 0;
+}
+
+static void addrec_db(void)
+{
+       int klen, dlen;
+       char *k, *d;
+       TDB_DATA key, data;
+
+       klen = 1 + (rand() % KEYLEN);
+       dlen = 1 + (rand() % DATALEN);
+
+       k = randbuf(klen);
+       d = randbuf(dlen);
+
+       key.dptr = (unsigned char *)k;
+       key.dsize = klen+1;
+
+       data.dptr = (unsigned char *)d;
+       data.dsize = dlen+1;
+
+#if REOPEN_PROB
+       if (in_traverse == 0 && in_transaction == 0 && random() % REOPEN_PROB == 0) {
+               tdb_reopen_all(0);
+               goto next;
+       } 
+#endif
+
+#if TRANSACTION_PROB
+       if (in_traverse == 0 && in_transaction == 0 && (always_transaction || random() % TRANSACTION_PROB == 0)) {
+               if (tdb_transaction_start(db) != 0) {
+                       fatal(db, "tdb_transaction_start failed");
+               }
+               in_transaction++;
+               goto next;
+       }
+       if (in_traverse == 0 && in_transaction && random() % TRANSACTION_PROB == 0) {
+               if (random() % TRANSACTION_PREPARE_PROB == 0) {
+                       if (tdb_transaction_prepare_commit(db) != 0) {
+                               fatal(db, "tdb_transaction_prepare_commit failed");
+                       }
+               }
+               if (tdb_transaction_commit(db) != 0) {
+                       fatal(db, "tdb_transaction_commit failed");
+               }
+               in_transaction--;
+               goto next;
+       }
+
+       if (in_traverse == 0 && in_transaction && random() % TRANSACTION_PROB == 0) {
+               tdb_transaction_cancel(db);
+               in_transaction--;
+               goto next;
+       }
+#endif
+
+#if DELETE_PROB
+       if (random() % DELETE_PROB == 0) {
+               tdb_delete(db, key);
+               goto next;
+       }
+#endif
+
+#if STORE_PROB
+       if (random() % STORE_PROB == 0) {
+               if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+                       fatal(db, "tdb_store failed");
+               }
+               goto next;
+       }
+#endif
+
+#if APPEND_PROB
+       if (random() % APPEND_PROB == 0) {
+               if (tdb_append(db, key, data) != 0) {
+                       fatal(db, "tdb_append failed");
+               }
+               goto next;
+       }
+#endif
+
+#if LOCKSTORE_PROB
+       if (random() % LOCKSTORE_PROB == 0) {
+               tdb_chainlock(db, key);
+               if (tdb_fetch(db, key, &data) != TDB_SUCCESS) {
+                       data.dsize = 0;
+                       data.dptr = NULL;
+               }
+               if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
+                       fatal(db, "tdb_store failed");
+               }
+               if (data.dptr) free(data.dptr);
+               tdb_chainunlock(db, key);
+               goto next;
+       } 
+#endif
+
+#if TRAVERSE_PROB
+       /* FIXME: recursive traverses break transactions? */
+       if (in_traverse == 0 && random() % TRAVERSE_PROB == 0) {
+               in_traverse++;
+               tdb_traverse(db, modify_traverse, NULL);
+               in_traverse--;
+               goto next;
+       }
+#endif
+
+       if (tdb_fetch(db, key, &data) == TDB_SUCCESS)
+               free(data.dptr);
+
+next:
+       free(k);
+       free(d);
+}
+
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
+                       void *state)
+{
+       tdb_delete(tdb, key);
+       return 0;
+}
+
+static void usage(void)
+{
+       printf("Usage: tdbtorture"
+#if TRANSACTION_PROB
+              " [-t]"
+#endif
+              " [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-S]\n");
+       exit(0);
+}
+
+static void send_count_and_suicide(int sig)
+{
+       /* This ensures our successor can continue where we left off. */
+       if (write(count_pipe, &loopnum, sizeof(loopnum)) != sizeof(loopnum))
+               exit(2);
+       /* This gives a unique signature. */
+       kill(getpid(), SIGUSR2);
+}
+
+static int run_child(int i, int seed, unsigned num_loops, unsigned start,
+                    int tdb_flags)
+{
+       struct sigaction act = { .sa_sigaction = segv_handler,
+                                .sa_flags = SA_SIGINFO };
+       sigaction(11, &act, NULL);      
+
+       db = tdb_open("torture.tdb", tdb_flags, O_RDWR | O_CREAT, 0600,
+                     &log_attr);
+       if (!db) {
+               fatal(NULL, "db open failed");
+       }
+
+#if 0
+       if (i == 0) {
+               printf("pid %i\n", getpid());
+               sleep(9);
+       } else
+               sleep(10);
+#endif
+
+       srand(seed + i);
+       srandom(seed + i);
+
+       /* Set global, then we're ready to handle being killed. */
+       loopnum = start;
+       signal(SIGUSR1, send_count_and_suicide);
+
+       for (;loopnum<num_loops && error_count == 0;loopnum++) {
+               addrec_db();
+       }
+
+       if (error_count == 0) {
+               tdb_traverse(db, NULL, NULL);
+#if TRANSACTION_PROB
+               if (always_transaction) {
+                       while (in_transaction) {
+                               tdb_transaction_cancel(db);
+                               in_transaction--;
+                       }
+                       if (tdb_transaction_start(db) != 0)
+                               fatal(db, "tdb_transaction_start failed");
+               }
+#endif
+               tdb_traverse(db, traverse_fn, NULL);
+               tdb_traverse(db, traverse_fn, NULL);
+
+#if TRANSACTION_PROB
+               if (always_transaction) {
+                       if (tdb_transaction_commit(db) != 0)
+                               fatal(db, "tdb_transaction_commit failed");
+               }
+#endif
+       }
+
+       tdb_close(db);
+
+       return (error_count < 100 ? error_count : 100);
+}
+
+int main(int argc, char * const *argv)
+{
+       int i, seed = -1;
+       int num_loops = 5000;
+       int num_procs = 3;
+       int c, pfds[2];
+       extern char *optarg;
+       pid_t *pids;
+       int kill_random = 0;
+       int *done;
+       int tdb_flags = TDB_DEFAULT;
+
+       log_attr.base.attr = TDB_ATTRIBUTE_LOG;
+       log_attr.base.next = &seed_attr;
+       log_attr.log.fn = tdb_log;
+       seed_attr.base.attr = TDB_ATTRIBUTE_SEED;
+
+       while ((c = getopt(argc, argv, "n:l:s:thkS")) != -1) {
+               switch (c) {
+               case 'n':
+                       num_procs = strtol(optarg, NULL, 0);
+                       break;
+               case 'l':
+                       num_loops = strtol(optarg, NULL, 0);
+                       break;
+               case 's':
+                       seed = strtol(optarg, NULL, 0);
+                       break;
+               case 'S':
+                       tdb_flags = TDB_NOSYNC;
+                       break;
+               case 't':
+#if TRANSACTION_PROB
+                       always_transaction = 1;
+#else
+                       fprintf(stderr, "Transactions not supported\n");
+                       usage();
+#endif
+                       break;
+               case 'k':
+                       kill_random = 1;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       unlink("torture.tdb");
+
+       if (seed == -1) {
+               seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
+       }
+       seed_attr.seed.seed = (((uint64_t)seed) << 32) | seed; 
+
+       if (num_procs == 1 && !kill_random) {
+               /* Don't fork for this case, makes debugging easier. */
+               error_count = run_child(0, seed, num_loops, 0, tdb_flags);
+               goto done;
+       }
+
+       pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
+       done = (int *)calloc(sizeof(int), num_procs);
+
+       if (pipe(pfds) != 0) {
+               perror("Creating pipe");
+               exit(1);
+       }
+       count_pipe = pfds[1];
+
+       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, seed=%d%s\n", 
+                                      num_procs, num_loops, seed, 
+#if TRANSACTION_PROB
+                                      always_transaction ? " (all within transactions)" : ""
+#else
+                                      ""
+#endif
+                                       );
+                       }
+                       exit(run_child(i, seed, num_loops, 0, tdb_flags));
+               }
+       }
+
+       while (num_procs) {
+               int status, j;
+               pid_t pid;
+
+               if (error_count != 0) {
+                       /* try and stop the test on any failure */
+                       for (j=0;j<num_procs;j++) {
+                               if (pids[j] != 0) {
+                                       kill(pids[j], SIGTERM);
+                               }
+                       }
+               }
+
+               pid = waitpid(-1, &status, kill_random ? WNOHANG : 0);
+               if (pid == 0) {
+                       struct timespec ts;
+
+                       /* Sleep for 1/10 second. */
+                       ts.tv_sec = 0;
+                       ts.tv_nsec = 100000000;
+                       nanosleep(&ts, NULL);
+
+                       /* Kill someone. */
+                       kill(pids[random() % num_procs], SIGUSR1);
+                       continue;
+               }
+
+               if (pid == -1) {
+                       perror("failed to wait for child\n");
+                       exit(1);
+               }
+
+               for (j=0;j<num_procs;j++) {
+                       if (pids[j] == pid) break;
+               }
+               if (j == num_procs) {
+                       printf("unknown child %d exited!?\n", (int)pid);
+                       exit(1);
+               }
+               if (WIFSIGNALED(status)) {
+                       if (WTERMSIG(status) == SIGUSR2
+                           || WTERMSIG(status) == SIGUSR1) {
+                               /* SIGUSR2 means they wrote to pipe. */
+                               if (WTERMSIG(status) == SIGUSR2) {
+                                       if (read(pfds[0], &done[j],
+                                                sizeof(done[j]))
+                                           != sizeof(done[j]))
+                                               err(1,
+                                                   "Short read from child?");
+                               }
+                               pids[j] = fork();
+                               if (pids[j] == 0)
+                                       exit(run_child(j, seed, num_loops,
+                                                      done[j], tdb_flags));
+                               printf("Restarting child %i for %u-%u\n",
+                                      j, done[j], num_loops);
+                               continue;
+                       }
+                       printf("child %d exited with signal %d\n",
+                              (int)pid, WTERMSIG(status));
+                       error_count++;
+               } else {
+                       if (WEXITSTATUS(status) != 0) {
+                               printf("child %d exited with status %d\n",
+                                      (int)pid, WEXITSTATUS(status));
+                               error_count++;
+                       }
+               }
+               memmove(&pids[j], &pids[j+1],
+                       (num_procs - j - 1)*sizeof(pids[0]));
+               num_procs--;
+       }
+
+       free(pids);
+
+done:
+       if (error_count == 0) {
+               db = tdb_open("torture.tdb", TDB_DEFAULT, O_RDWR | O_CREAT,
+                             0600, &log_attr);
+               if (!db) {
+                       fatal(db, "db open failed");
+                       exit(1);
+               }
+               if (tdb_check(db, NULL, NULL) != 0) {
+                       fatal(db, "db check failed");
+                       exit(1);
+               }
+               tdb_close(db);
+               printf("OK\n");
+       }
+
+       return error_count;
+}
diff --git a/ccan/tdb2/tools/tdbtool.c b/ccan/tdb2/tools/tdbtool.c
deleted file mode 100644 (file)
index 262253c..0000000
+++ /dev/null
@@ -1,798 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Samba database functions
-   Copyright (C) Andrew Tridgell              1999-2000
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000
-   Copyright (C) Andrew Esh                        2001
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ccan/tdb2/tdb2.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <stdarg.h>
-
-static int do_command(void);
-const char *cmdname;
-char *arg1, *arg2;
-size_t arg1len, arg2len;
-int bIterate = 0;
-char *line;
-TDB_DATA iterate_kbuf;
-char cmdline[1024];
-static int disable_mmap;
-
-enum commands {
-       CMD_CREATE_TDB,
-       CMD_OPEN_TDB,
-       CMD_TRANSACTION_START,
-       CMD_TRANSACTION_COMMIT,
-       CMD_TRANSACTION_CANCEL,
-       CMD_ERASE,
-       CMD_DUMP,
-       CMD_INSERT,
-       CMD_MOVE,
-       CMD_STORE,
-       CMD_SHOW,
-       CMD_KEYS,
-       CMD_HEXKEYS,
-       CMD_DELETE,
-#if 0
-       CMD_LIST_HASH_FREE,
-       CMD_LIST_FREE,
-#endif
-       CMD_INFO,
-       CMD_MMAP,
-       CMD_SPEED,
-       CMD_FIRST,
-       CMD_NEXT,
-       CMD_SYSTEM,
-       CMD_CHECK,
-       CMD_QUIT,
-       CMD_HELP
-};
-
-typedef struct {
-       const char *name;
-       enum commands cmd;
-} COMMAND_TABLE;
-
-COMMAND_TABLE cmd_table[] = {
-       {"create",      CMD_CREATE_TDB},
-       {"open",        CMD_OPEN_TDB},
-#if 0
-       {"transaction_start",   CMD_TRANSACTION_START},
-       {"transaction_commit",  CMD_TRANSACTION_COMMIT},
-       {"transaction_cancel",  CMD_TRANSACTION_CANCEL},
-#endif
-       {"erase",       CMD_ERASE},
-       {"dump",        CMD_DUMP},
-       {"insert",      CMD_INSERT},
-       {"move",        CMD_MOVE},
-       {"store",       CMD_STORE},
-       {"show",        CMD_SHOW},
-       {"keys",        CMD_KEYS},
-       {"hexkeys",     CMD_HEXKEYS},
-       {"delete",      CMD_DELETE},
-#if 0
-       {"list",        CMD_LIST_HASH_FREE},
-       {"free",        CMD_LIST_FREE},
-#endif
-       {"info",        CMD_INFO},
-       {"speed",       CMD_SPEED},
-       {"mmap",        CMD_MMAP},
-       {"first",       CMD_FIRST},
-       {"1",           CMD_FIRST},
-       {"next",        CMD_NEXT},
-       {"n",           CMD_NEXT},
-       {"check",       CMD_CHECK},
-       {"quit",        CMD_QUIT},
-       {"q",           CMD_QUIT},
-       {"!",           CMD_SYSTEM},
-       {NULL,          CMD_HELP}
-};
-
-struct timeval tp1,tp2;
-
-static void _start_timer(void)
-{
-       gettimeofday(&tp1,NULL);
-}
-
-static double _end_timer(void)
-{
-       gettimeofday(&tp2,NULL);
-       return((tp2.tv_sec - tp1.tv_sec) + 
-              (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
-}
-
-static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
-                   const char *message, void *priv)
-{
-       fputs(message, stderr);
-}
-
-/* a tdb tool for manipulating a tdb database */
-
-static struct tdb_context *tdb;
-
-static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
-static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
-static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
-
-static void print_asc(const char *buf,int len)
-{
-       int i;
-
-       /* We're probably printing ASCII strings so don't try to display
-          the trailing NULL character. */
-
-       if (buf[len - 1] == 0)
-               len--;
-
-       for (i=0;i<len;i++)
-               printf("%c",isprint(buf[i])?buf[i]:'.');
-}
-
-static void print_data(const char *buf,int len)
-{
-       int i=0;
-       if (len<=0) return;
-       printf("[%03X] ",i);
-       for (i=0;i<len;) {
-               printf("%02X ",(int)((unsigned char)buf[i]));
-               i++;
-               if (i%8 == 0) printf(" ");
-               if (i%16 == 0) {      
-                       print_asc(&buf[i-16],8); printf(" ");
-                       print_asc(&buf[i-8],8); printf("\n");
-                       if (i<len) printf("[%03X] ",i);
-               }
-       }
-       if (i%16) {
-               int n;
-               
-               n = 16 - (i%16);
-               printf(" ");
-               if (n>8) printf(" ");
-               while (n--) printf("   ");
-               
-               n = i%16;
-               if (n > 8) n = 8;
-               print_asc(&buf[i-(i%16)],n); printf(" ");
-               n = (i%16) - n;
-               if (n>0) print_asc(&buf[i-n],n); 
-               printf("\n");    
-       }
-}
-
-static void help(void)
-{
-       printf("\n"
-"tdbtool: \n"
-"  create    dbname     : create a database\n"
-"  open      dbname     : open an existing database\n"
-"  openjh    dbname     : open an existing database (jenkins hash)\n"
-"  transaction_start    : start a transaction\n"
-"  transaction_commit   : commit a transaction\n"
-"  transaction_cancel   : cancel a transaction\n"
-"  erase                : erase the database\n"
-"  dump                 : dump the database as strings\n"
-"  keys                 : dump the database keys as strings\n"
-"  hexkeys              : dump the database keys as hex values\n"
-"  info                 : print summary info about the database\n"
-"  insert    key  data  : insert a record\n"
-"  move      key  file  : move a record to a destination tdb\n"
-"  store     key  data  : store a record (replace)\n"
-"  show      key        : show a record by key\n"
-"  delete    key        : delete a record by key\n"
-#if 0
-"  list                 : print the database hash table and freelist\n"
-"  free                 : print the database freelist\n"
-#endif
-"  check                : check the integrity of an opened database\n"
-"  speed                : perform speed tests on the database\n"
-"  ! command            : execute system command\n"
-"  1 | first            : print the first record\n"
-"  n | next             : print the next record\n"
-"  q | quit             : terminate\n"
-"  \\n                   : repeat 'next' command\n"
-"\n");
-}
-
-static void terror(enum TDB_ERROR err, const char *why)
-{
-       if (err != TDB_SUCCESS)
-               printf("%s:%s\n", tdb_errorstr(err), why);
-       else
-               printf("%s\n", why);
-}
-
-static void create_tdb(const char *tdbname)
-{
-       union tdb_attribute log_attr;
-       log_attr.base.attr = TDB_ATTRIBUTE_LOG;
-       log_attr.base.next = NULL;
-       log_attr.log.fn = tdb_log;
-
-       if (tdb) tdb_close(tdb);
-       tdb = tdb_open(tdbname, (disable_mmap?TDB_NOMMAP:0),
-                      O_RDWR | O_CREAT | O_TRUNC, 0600, &log_attr);
-       if (!tdb) {
-               printf("Could not create %s: %s\n", tdbname, strerror(errno));
-       }
-}
-
-static void open_tdb(const char *tdbname)
-{
-       union tdb_attribute log_attr;
-       log_attr.base.attr = TDB_ATTRIBUTE_LOG;
-       log_attr.base.next = NULL;
-       log_attr.log.fn = tdb_log;
-
-       if (tdb) tdb_close(tdb);
-       tdb = tdb_open(tdbname, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
-                      &log_attr);
-       if (!tdb) {
-               printf("Could not open %s: %s\n", tdbname, strerror(errno));
-       }
-}
-
-static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
-{
-       TDB_DATA key, dbuf;
-       enum TDB_ERROR ecode;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror(TDB_SUCCESS, "need key");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-       dbuf.dptr = (unsigned char *)data;
-       dbuf.dsize = datalen;
-
-       ecode = tdb_store(tdb, key, dbuf, TDB_INSERT);
-       if (ecode) {
-               terror(ecode, "insert failed");
-       }
-}
-
-static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
-{
-       TDB_DATA key, dbuf;
-       enum TDB_ERROR ecode;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror(TDB_SUCCESS, "need key");
-               return;
-       }
-
-       if ((data == NULL) || (datalen == 0)) {
-               terror(TDB_SUCCESS, "need data");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-       dbuf.dptr = (unsigned char *)data;
-       dbuf.dsize = datalen;
-
-       printf("Storing key:\n");
-       print_rec(tdb, key, dbuf, NULL);
-
-       ecode = tdb_store(tdb, key, dbuf, TDB_REPLACE);
-       if (ecode) {
-               terror(ecode, "store failed");
-       }
-}
-
-static void show_tdb(char *keyname, size_t keylen)
-{
-       TDB_DATA key, dbuf;
-       enum TDB_ERROR ecode;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror(TDB_SUCCESS, "need key");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-
-       ecode = tdb_fetch(tdb, key, &dbuf);
-       if (ecode) {
-               terror(ecode, "fetch failed");
-               return;
-       }
-       
-       print_rec(tdb, key, dbuf, NULL);
-       
-       free( dbuf.dptr );
-}
-
-static void delete_tdb(char *keyname, size_t keylen)
-{
-       TDB_DATA key;
-       enum TDB_ERROR ecode;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror(TDB_SUCCESS, "need key");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-
-       ecode = tdb_delete(tdb, key);
-       if (ecode) {
-               terror(ecode, "delete failed");
-       }
-}
-
-static void move_rec(char *keyname, size_t keylen, char* tdbname)
-{
-       TDB_DATA key, dbuf;
-       struct tdb_context *dst_tdb;
-       enum TDB_ERROR ecode;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror(TDB_SUCCESS, "need key");
-               return;
-       }
-
-       if ( !tdbname ) {
-               terror(TDB_SUCCESS, "need destination tdb name");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-
-       ecode = tdb_fetch(tdb, key, &dbuf);
-       if (ecode) {
-               terror(ecode, "fetch failed");
-               return;
-       }
-       
-       print_rec(tdb, key, dbuf, NULL);
-       
-       dst_tdb = tdb_open(tdbname, 0, O_RDWR, 0600, NULL);
-       if ( !dst_tdb ) {
-               terror(TDB_SUCCESS, "unable to open destination tdb");
-               return;
-       }
-       
-       ecode = tdb_store( dst_tdb, key, dbuf, TDB_REPLACE);
-       if (ecode)
-               terror(ecode, "failed to move record");
-       else
-               printf("record moved\n");
-       
-       tdb_close( dst_tdb );
-}
-
-static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("\nkey %d bytes\n", (int)key.dsize);
-       print_asc((const char *)key.dptr, key.dsize);
-       printf("\ndata %d bytes\n", (int)dbuf.dsize);
-       print_data((const char *)dbuf.dptr, dbuf.dsize);
-       return 0;
-}
-
-static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("key %d bytes: ", (int)key.dsize);
-       print_asc((const char *)key.dptr, key.dsize);
-       printf("\n");
-       return 0;
-}
-
-static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("key %d bytes\n", (int)key.dsize);
-       print_data((const char *)key.dptr, key.dsize);
-       printf("\n");
-       return 0;
-}
-
-static int total_bytes;
-
-static int traverse_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       total_bytes += dbuf.dsize;
-       return 0;
-}
-
-static void info_tdb(void)
-{
-       enum TDB_ERROR ecode;
-       char *summary;
-
-       ecode = tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &summary);
-
-       if (ecode) {
-               terror(ecode, "Getting summary");
-       } else {
-               printf("%s", summary);
-               free(summary);
-       }
-}
-
-static void speed_tdb(const char *tlimit)
-{
-       unsigned timelimit = tlimit?atoi(tlimit):0;
-       double t;
-       int ops;
-       if (timelimit == 0) timelimit = 5;
-
-       ops = 0;
-       printf("Testing store speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               long int r = random();
-               TDB_DATA key, dbuf;
-               key = tdb_mkdata("store test", strlen("store test"));
-               dbuf.dptr = (unsigned char *)&r;
-               dbuf.dsize = sizeof(r);
-               tdb_store(tdb, key, dbuf, TDB_REPLACE);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-
-       ops = 0;
-       printf("Testing fetch speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               long int r = random();
-               TDB_DATA key, dbuf;
-               key = tdb_mkdata("store test", strlen("store test"));
-               dbuf.dptr = (unsigned char *)&r;
-               dbuf.dsize = sizeof(r);
-               tdb_fetch(tdb, key, &dbuf);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-
-       ops = 0;
-       printf("Testing transaction speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               long int r = random();
-               TDB_DATA key, dbuf;
-               key = tdb_mkdata("transaction test", strlen("transaction test"));
-               dbuf.dptr = (unsigned char *)&r;
-               dbuf.dsize = sizeof(r);
-               tdb_transaction_start(tdb);
-               tdb_store(tdb, key, dbuf, TDB_REPLACE);
-               tdb_transaction_commit(tdb);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-
-       ops = 0;
-       printf("Testing traverse speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               tdb_traverse(tdb, traverse_fn, NULL);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-}
-
-static void toggle_mmap(void)
-{
-       disable_mmap = !disable_mmap;
-       if (disable_mmap) {
-               printf("mmap is disabled\n");
-       } else {
-               printf("mmap is enabled\n");
-       }
-}
-
-static char *tdb_getline(const char *prompt)
-{
-       static char thisline[1024];
-       char *p;
-       fputs(prompt, stdout);
-       thisline[0] = 0;
-       p = fgets(thisline, sizeof(thisline)-1, stdin);
-       if (p) p = strchr(p, '\n');
-       if (p) *p = 0;
-       return p?thisline:NULL;
-}
-
-static int do_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
-                     void *state)
-{
-    return tdb_delete(the_tdb, key);
-}
-
-static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
-{
-       TDB_DATA dbuf;
-       enum TDB_ERROR ecode;
-       ecode = tdb_firstkey(the_tdb, pkey);
-       if (!ecode)
-               ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
-       if (ecode) terror(ecode, "fetch failed");
-       else {
-               print_rec(the_tdb, *pkey, dbuf, NULL);
-       }
-}
-
-static void next_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
-{
-       TDB_DATA dbuf;
-       enum TDB_ERROR ecode;
-       ecode = tdb_nextkey(the_tdb, pkey);
-
-       if (!ecode)
-               ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
-       if (ecode) 
-               terror(ecode, "fetch failed");
-       else
-               print_rec(the_tdb, *pkey, dbuf, NULL);
-}
-
-static void check_db(struct tdb_context *the_tdb)
-{
-       if (!the_tdb) {
-               printf("Error: No database opened!\n");
-       } else {
-               if (tdb_check(the_tdb, NULL, NULL) != 0)
-                       printf("Integrity check for the opened database failed.\n");
-               else
-                       printf("Database integrity is OK.\n");
-       }
-}
-
-static int do_command(void)
-{
-       COMMAND_TABLE *ctp = cmd_table;
-       enum commands mycmd = CMD_HELP;
-       int cmd_len;
-
-       if (cmdname && strlen(cmdname) == 0) {
-               mycmd = CMD_NEXT;
-       } else {
-               while (ctp->name) {
-                       cmd_len = strlen(ctp->name);
-                       if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
-                               mycmd = ctp->cmd;
-                               break;
-                       }
-                       ctp++;
-               }
-       }
-
-       switch (mycmd) {
-       case CMD_CREATE_TDB:
-               bIterate = 0;
-               create_tdb(arg1);
-               return 0;
-       case CMD_OPEN_TDB:
-               bIterate = 0;
-               open_tdb(arg1);
-               return 0;
-       case CMD_SYSTEM:
-               /* Shell command */
-               if (system(arg1) == -1) {
-                       terror(TDB_SUCCESS, "system() call failed\n");
-               }
-               return 0;
-       case CMD_QUIT:
-               return 1;
-       default:
-               /* all the rest require a open database */
-               if (!tdb) {
-                       bIterate = 0;
-                       terror(TDB_SUCCESS, "database not open");
-                       help();
-                       return 0;
-               }
-               switch (mycmd) {
-               case CMD_TRANSACTION_START:
-                       bIterate = 0;
-                       tdb_transaction_start(tdb);
-                       return 0;
-               case CMD_TRANSACTION_COMMIT:
-                       bIterate = 0;
-                       tdb_transaction_commit(tdb);
-                       return 0;
-               case CMD_TRANSACTION_CANCEL:
-                       bIterate = 0;
-                       tdb_transaction_cancel(tdb);
-                       return 0;
-               case CMD_ERASE:
-                       bIterate = 0;
-                       tdb_traverse(tdb, do_delete_fn, NULL);
-                       return 0;
-               case CMD_DUMP:
-                       bIterate = 0;
-                       tdb_traverse(tdb, print_rec, NULL);
-                       return 0;
-               case CMD_INSERT:
-                       bIterate = 0;
-                       insert_tdb(arg1, arg1len,arg2,arg2len);
-                       return 0;
-               case CMD_MOVE:
-                       bIterate = 0;
-                       move_rec(arg1,arg1len,arg2);
-                       return 0;
-               case CMD_STORE:
-                       bIterate = 0;
-                       store_tdb(arg1,arg1len,arg2,arg2len);
-                       return 0;
-               case CMD_SHOW:
-                       bIterate = 0;
-                       show_tdb(arg1, arg1len);
-                       return 0;
-               case CMD_KEYS:
-                       tdb_traverse(tdb, print_key, NULL);
-                       return 0;
-               case CMD_HEXKEYS:
-                       tdb_traverse(tdb, print_hexkey, NULL);
-                       return 0;
-               case CMD_DELETE:
-                       bIterate = 0;
-                       delete_tdb(arg1,arg1len);
-                       return 0;
-#if 0
-               case CMD_LIST_HASH_FREE:
-                       tdb_dump_all(tdb);
-                       return 0;
-               case CMD_LIST_FREE:
-                       tdb_printfreelist(tdb);
-                       return 0;
-#endif
-               case CMD_INFO:
-                       info_tdb();
-                       return 0;
-               case CMD_SPEED:
-                       speed_tdb(arg1);
-                       return 0;
-               case CMD_MMAP:
-                       toggle_mmap();
-                       return 0;
-               case CMD_FIRST:
-                       bIterate = 1;
-                       first_record(tdb, &iterate_kbuf);
-                       return 0;
-               case CMD_NEXT:
-                       if (bIterate)
-                               next_record(tdb, &iterate_kbuf);
-                       return 0;
-               case CMD_CHECK:
-                       check_db(tdb);
-                       return 0;
-               case CMD_HELP:
-                       help();
-                       return 0;
-               case CMD_CREATE_TDB:
-               case CMD_OPEN_TDB:
-               case CMD_SYSTEM:
-               case CMD_QUIT:
-                       /*
-                        * unhandled commands.  cases included here to avoid compiler
-                        * warnings.
-                        */
-                       return 0;
-               }
-       }
-
-       return 0;
-}
-
-static char *convert_string(char *instring, size_t *sizep)
-{
-       size_t length = 0;
-       char *outp, *inp;
-       char temp[3];
-
-       outp = inp = instring;
-
-       while (*inp) {
-               if (*inp == '\\') {
-                       inp++;
-                       if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
-                               temp[0] = *inp++;
-                               temp[1] = '\0';
-                               if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
-                                       temp[1] = *inp++;
-                                       temp[2] = '\0';
-                               }
-                               *outp++ = (char)strtol((const char *)temp,NULL,16);
-                       } else {
-                               *outp++ = *inp++;
-                       }
-               } else {
-                       *outp++ = *inp++;
-               }
-               length++;
-       }
-       *sizep = length;
-       return instring;
-}
-
-int main(int argc, char *argv[])
-{
-       cmdname = "";
-       arg1 = NULL;
-       arg1len = 0;
-       arg2 = NULL;
-       arg2len = 0;
-
-       if (argv[1]) {
-               cmdname = "open";
-               arg1 = argv[1];
-               do_command();
-               cmdname =  "";
-               arg1 = NULL;
-       }
-
-       switch (argc) {
-       case 1:
-       case 2:
-               /* Interactive mode */
-               while ((cmdname = tdb_getline("tdb> "))) {
-                       arg2 = arg1 = NULL;
-                       if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
-                               arg1++;
-                               arg2 = arg1;
-                               while (*arg2) {
-                                       if (*arg2 == ' ') {
-                                               *arg2++ = '\0';
-                                               break;
-                                       }
-                                       if ((*arg2++ == '\\') && (*arg2 == ' ')) {
-                                               arg2++;
-                                       }
-                               }
-                       }
-                       if (arg1) arg1 = convert_string(arg1,&arg1len);
-                       if (arg2) arg2 = convert_string(arg2,&arg2len);
-                       if (do_command()) break;
-               }
-               break;
-       case 5:
-               arg2 = convert_string(argv[4],&arg2len);
-       case 4:
-               arg1 = convert_string(argv[3],&arg1len);
-       case 3:
-               cmdname = argv[2];
-       default:
-               do_command();
-               break;
-       }
-
-       if (tdb) tdb_close(tdb);
-
-       return 0;
-}
diff --git a/ccan/tdb2/tools/tdbtorture.c b/ccan/tdb2/tools/tdbtorture.c
deleted file mode 100644 (file)
index 32d7ea3..0000000
+++ /dev/null
@@ -1,494 +0,0 @@
-/* this tests tdb by doing lots of ops from several simultaneous
-   writers - that stresses the locking code. 
-*/
-
-#include <ccan/tdb2/tdb2.h>
-#include <stdlib.h>
-#include <err.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/wait.h>
-
-//#define REOPEN_PROB 30
-#define DELETE_PROB 8
-#define STORE_PROB 4
-#define APPEND_PROB 6
-#define TRANSACTION_PROB 10
-#define TRANSACTION_PREPARE_PROB 2
-#define LOCKSTORE_PROB 5
-#define TRAVERSE_PROB 20
-#define TRAVERSE_MOD_PROB 100
-#define TRAVERSE_ABORT_PROB 500
-#define CULL_PROB 100
-#define KEYLEN 3
-#define DATALEN 100
-
-static struct tdb_context *db;
-static int in_transaction;
-static int in_traverse;
-static int error_count;
-#if TRANSACTION_PROB
-static int always_transaction = 0;
-#endif
-static int loopnum;
-static int count_pipe;
-static union tdb_attribute log_attr;
-static union tdb_attribute seed_attr;
-
-static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
-                   const char *message, void *data)
-{
-       fputs(message, stdout);
-       fflush(stdout);
-#if 0
-       {
-               char str[200];
-               signal(SIGUSR1, SIG_IGN);
-               sprintf(str,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
-               system(str);
-       }
-#endif 
-}
-
-#include "../private.h"
-
-static void segv_handler(int sig, siginfo_t *info, void *p)
-{
-       char string[100];
-
-       sprintf(string, "%u: death at %p (map_ptr %p, map_size %zu)\n",
-               getpid(), info->si_addr, db->file->map_ptr,
-               (size_t)db->file->map_size);
-       if (write(2, string, strlen(string)) > 0)
-               sleep(60);
-       _exit(11);
-}      
-
-static void fatal(struct tdb_context *tdb, const char *why)
-{
-       fprintf(stderr, "%u:%s:%s\n", getpid(), why,
-               tdb ? tdb_errorstr(tdb_error(tdb)) : "(no tdb)");
-       error_count++;
-}
-
-static char *randbuf(int len)
-{
-       char *buf;
-       int i;
-       buf = (char *)malloc(len+1);
-
-       for (i=0;i<len;i++) {
-               buf[i] = 'a' + (rand() % 26);
-       }
-       buf[i] = 0;
-       return buf;
-}
-
-static void addrec_db(void);
-static int modify_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
-                          void *state)
-{
-#if CULL_PROB
-       if (random() % CULL_PROB == 0) {
-               tdb_delete(tdb, key);
-       }
-#endif
-
-#if TRAVERSE_MOD_PROB
-       if (random() % TRAVERSE_MOD_PROB == 0) {
-               addrec_db();
-       }
-#endif
-
-#if TRAVERSE_ABORT_PROB
-       if (random() % TRAVERSE_ABORT_PROB == 0)
-               return 1;
-#endif
-
-       return 0;
-}
-
-static void addrec_db(void)
-{
-       int klen, dlen;
-       char *k, *d;
-       TDB_DATA key, data;
-
-       klen = 1 + (rand() % KEYLEN);
-       dlen = 1 + (rand() % DATALEN);
-
-       k = randbuf(klen);
-       d = randbuf(dlen);
-
-       key.dptr = (unsigned char *)k;
-       key.dsize = klen+1;
-
-       data.dptr = (unsigned char *)d;
-       data.dsize = dlen+1;
-
-#if REOPEN_PROB
-       if (in_traverse == 0 && in_transaction == 0 && random() % REOPEN_PROB == 0) {
-               tdb_reopen_all(0);
-               goto next;
-       } 
-#endif
-
-#if TRANSACTION_PROB
-       if (in_traverse == 0 && in_transaction == 0 && (always_transaction || random() % TRANSACTION_PROB == 0)) {
-               if (tdb_transaction_start(db) != 0) {
-                       fatal(db, "tdb_transaction_start failed");
-               }
-               in_transaction++;
-               goto next;
-       }
-       if (in_traverse == 0 && in_transaction && random() % TRANSACTION_PROB == 0) {
-               if (random() % TRANSACTION_PREPARE_PROB == 0) {
-                       if (tdb_transaction_prepare_commit(db) != 0) {
-                               fatal(db, "tdb_transaction_prepare_commit failed");
-                       }
-               }
-               if (tdb_transaction_commit(db) != 0) {
-                       fatal(db, "tdb_transaction_commit failed");
-               }
-               in_transaction--;
-               goto next;
-       }
-
-       if (in_traverse == 0 && in_transaction && random() % TRANSACTION_PROB == 0) {
-               tdb_transaction_cancel(db);
-               in_transaction--;
-               goto next;
-       }
-#endif
-
-#if DELETE_PROB
-       if (random() % DELETE_PROB == 0) {
-               tdb_delete(db, key);
-               goto next;
-       }
-#endif
-
-#if STORE_PROB
-       if (random() % STORE_PROB == 0) {
-               if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
-                       fatal(db, "tdb_store failed");
-               }
-               goto next;
-       }
-#endif
-
-#if APPEND_PROB
-       if (random() % APPEND_PROB == 0) {
-               if (tdb_append(db, key, data) != 0) {
-                       fatal(db, "tdb_append failed");
-               }
-               goto next;
-       }
-#endif
-
-#if LOCKSTORE_PROB
-       if (random() % LOCKSTORE_PROB == 0) {
-               tdb_chainlock(db, key);
-               if (tdb_fetch(db, key, &data) != TDB_SUCCESS) {
-                       data.dsize = 0;
-                       data.dptr = NULL;
-               }
-               if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
-                       fatal(db, "tdb_store failed");
-               }
-               if (data.dptr) free(data.dptr);
-               tdb_chainunlock(db, key);
-               goto next;
-       } 
-#endif
-
-#if TRAVERSE_PROB
-       /* FIXME: recursive traverses break transactions? */
-       if (in_traverse == 0 && random() % TRAVERSE_PROB == 0) {
-               in_traverse++;
-               tdb_traverse(db, modify_traverse, NULL);
-               in_traverse--;
-               goto next;
-       }
-#endif
-
-       if (tdb_fetch(db, key, &data) == TDB_SUCCESS)
-               free(data.dptr);
-
-next:
-       free(k);
-       free(d);
-}
-
-static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
-                       void *state)
-{
-       tdb_delete(tdb, key);
-       return 0;
-}
-
-static void usage(void)
-{
-       printf("Usage: tdbtorture"
-#if TRANSACTION_PROB
-              " [-t]"
-#endif
-              " [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-S]\n");
-       exit(0);
-}
-
-static void send_count_and_suicide(int sig)
-{
-       /* This ensures our successor can continue where we left off. */
-       if (write(count_pipe, &loopnum, sizeof(loopnum)) != sizeof(loopnum))
-               exit(2);
-       /* This gives a unique signature. */
-       kill(getpid(), SIGUSR2);
-}
-
-static int run_child(int i, int seed, unsigned num_loops, unsigned start,
-                    int tdb_flags)
-{
-       struct sigaction act = { .sa_sigaction = segv_handler,
-                                .sa_flags = SA_SIGINFO };
-       sigaction(11, &act, NULL);      
-
-       db = tdb_open("torture.tdb", tdb_flags, O_RDWR | O_CREAT, 0600,
-                     &log_attr);
-       if (!db) {
-               fatal(NULL, "db open failed");
-       }
-
-#if 0
-       if (i == 0) {
-               printf("pid %i\n", getpid());
-               sleep(9);
-       } else
-               sleep(10);
-#endif
-
-       srand(seed + i);
-       srandom(seed + i);
-
-       /* Set global, then we're ready to handle being killed. */
-       loopnum = start;
-       signal(SIGUSR1, send_count_and_suicide);
-
-       for (;loopnum<num_loops && error_count == 0;loopnum++) {
-               addrec_db();
-       }
-
-       if (error_count == 0) {
-               tdb_traverse(db, NULL, NULL);
-#if TRANSACTION_PROB
-               if (always_transaction) {
-                       while (in_transaction) {
-                               tdb_transaction_cancel(db);
-                               in_transaction--;
-                       }
-                       if (tdb_transaction_start(db) != 0)
-                               fatal(db, "tdb_transaction_start failed");
-               }
-#endif
-               tdb_traverse(db, traverse_fn, NULL);
-               tdb_traverse(db, traverse_fn, NULL);
-
-#if TRANSACTION_PROB
-               if (always_transaction) {
-                       if (tdb_transaction_commit(db) != 0)
-                               fatal(db, "tdb_transaction_commit failed");
-               }
-#endif
-       }
-
-       tdb_close(db);
-
-       return (error_count < 100 ? error_count : 100);
-}
-
-int main(int argc, char * const *argv)
-{
-       int i, seed = -1;
-       int num_loops = 5000;
-       int num_procs = 3;
-       int c, pfds[2];
-       extern char *optarg;
-       pid_t *pids;
-       int kill_random = 0;
-       int *done;
-       int tdb_flags = TDB_DEFAULT;
-
-       log_attr.base.attr = TDB_ATTRIBUTE_LOG;
-       log_attr.base.next = &seed_attr;
-       log_attr.log.fn = tdb_log;
-       seed_attr.base.attr = TDB_ATTRIBUTE_SEED;
-
-       while ((c = getopt(argc, argv, "n:l:s:thkS")) != -1) {
-               switch (c) {
-               case 'n':
-                       num_procs = strtol(optarg, NULL, 0);
-                       break;
-               case 'l':
-                       num_loops = strtol(optarg, NULL, 0);
-                       break;
-               case 's':
-                       seed = strtol(optarg, NULL, 0);
-                       break;
-               case 'S':
-                       tdb_flags = TDB_NOSYNC;
-                       break;
-               case 't':
-#if TRANSACTION_PROB
-                       always_transaction = 1;
-#else
-                       fprintf(stderr, "Transactions not supported\n");
-                       usage();
-#endif
-                       break;
-               case 'k':
-                       kill_random = 1;
-                       break;
-               default:
-                       usage();
-               }
-       }
-
-       unlink("torture.tdb");
-
-       if (seed == -1) {
-               seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
-       }
-       seed_attr.seed.seed = (((uint64_t)seed) << 32) | seed; 
-
-       if (num_procs == 1 && !kill_random) {
-               /* Don't fork for this case, makes debugging easier. */
-               error_count = run_child(0, seed, num_loops, 0, tdb_flags);
-               goto done;
-       }
-
-       pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
-       done = (int *)calloc(sizeof(int), num_procs);
-
-       if (pipe(pfds) != 0) {
-               perror("Creating pipe");
-               exit(1);
-       }
-       count_pipe = pfds[1];
-
-       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, seed=%d%s\n", 
-                                      num_procs, num_loops, seed, 
-#if TRANSACTION_PROB
-                                      always_transaction ? " (all within transactions)" : ""
-#else
-                                      ""
-#endif
-                                       );
-                       }
-                       exit(run_child(i, seed, num_loops, 0, tdb_flags));
-               }
-       }
-
-       while (num_procs) {
-               int status, j;
-               pid_t pid;
-
-               if (error_count != 0) {
-                       /* try and stop the test on any failure */
-                       for (j=0;j<num_procs;j++) {
-                               if (pids[j] != 0) {
-                                       kill(pids[j], SIGTERM);
-                               }
-                       }
-               }
-
-               pid = waitpid(-1, &status, kill_random ? WNOHANG : 0);
-               if (pid == 0) {
-                       struct timespec ts;
-
-                       /* Sleep for 1/10 second. */
-                       ts.tv_sec = 0;
-                       ts.tv_nsec = 100000000;
-                       nanosleep(&ts, NULL);
-
-                       /* Kill someone. */
-                       kill(pids[random() % num_procs], SIGUSR1);
-                       continue;
-               }
-
-               if (pid == -1) {
-                       perror("failed to wait for child\n");
-                       exit(1);
-               }
-
-               for (j=0;j<num_procs;j++) {
-                       if (pids[j] == pid) break;
-               }
-               if (j == num_procs) {
-                       printf("unknown child %d exited!?\n", (int)pid);
-                       exit(1);
-               }
-               if (WIFSIGNALED(status)) {
-                       if (WTERMSIG(status) == SIGUSR2
-                           || WTERMSIG(status) == SIGUSR1) {
-                               /* SIGUSR2 means they wrote to pipe. */
-                               if (WTERMSIG(status) == SIGUSR2) {
-                                       if (read(pfds[0], &done[j],
-                                                sizeof(done[j]))
-                                           != sizeof(done[j]))
-                                               err(1,
-                                                   "Short read from child?");
-                               }
-                               pids[j] = fork();
-                               if (pids[j] == 0)
-                                       exit(run_child(j, seed, num_loops,
-                                                      done[j], tdb_flags));
-                               printf("Restarting child %i for %u-%u\n",
-                                      j, done[j], num_loops);
-                               continue;
-                       }
-                       printf("child %d exited with signal %d\n",
-                              (int)pid, WTERMSIG(status));
-                       error_count++;
-               } else {
-                       if (WEXITSTATUS(status) != 0) {
-                               printf("child %d exited with status %d\n",
-                                      (int)pid, WEXITSTATUS(status));
-                               error_count++;
-                       }
-               }
-               memmove(&pids[j], &pids[j+1],
-                       (num_procs - j - 1)*sizeof(pids[0]));
-               num_procs--;
-       }
-
-       free(pids);
-
-done:
-       if (error_count == 0) {
-               db = tdb_open("torture.tdb", TDB_DEFAULT, O_RDWR | O_CREAT,
-                             0600, &log_attr);
-               if (!db) {
-                       fatal(db, "db open failed");
-                       exit(1);
-               }
-               if (tdb_check(db, NULL, NULL) != 0) {
-                       fatal(db, "db check failed");
-                       exit(1);
-               }
-               tdb_close(db);
-               printf("OK\n");
-       }
-
-       return error_count;
-}