root/lib/tdb/tools/tdbtorture.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tdb_log
  2. fatal
  3. randbuf
  4. cull_traverse
  5. addrec_db
  6. traverse_fn
  7. usage
  8. main

   1 /* this tests tdb by doing lots of ops from several simultaneous
   2    writers - that stresses the locking code. 
   3 */
   4 
   5 #include "replace.h"
   6 #include "system/time.h"
   7 #include "system/wait.h"
   8 #include "system/filesys.h"
   9 #include "tdb.h"
  10 
  11 #ifdef HAVE_GETOPT_H
  12 #include <getopt.h>
  13 #endif
  14 
  15 
  16 #define REOPEN_PROB 30
  17 #define DELETE_PROB 8
  18 #define STORE_PROB 4
  19 #define APPEND_PROB 6
  20 #define TRANSACTION_PROB 10
  21 #define LOCKSTORE_PROB 5
  22 #define TRAVERSE_PROB 20
  23 #define TRAVERSE_READ_PROB 20
  24 #define CULL_PROB 100
  25 #define KEYLEN 3
  26 #define DATALEN 100
  27 
  28 static struct tdb_context *db;
  29 static int in_transaction;
  30 static int error_count;
  31 
  32 #ifdef PRINTF_ATTRIBUTE
  33 static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     /* [<][>][^][v][top][bottom][index][help] */
  34 #endif
  35 static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
  36 {
  37         va_list ap;
  38     
  39         error_count++;
  40 
  41         va_start(ap, format);
  42         vfprintf(stdout, format, ap);
  43         va_end(ap);
  44         fflush(stdout);
  45 #if 0
  46         {
  47                 char *ptr;
  48                 asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
  49                 system(ptr);
  50                 free(ptr);
  51         }
  52 #endif  
  53 }
  54 
  55 static void fatal(const char *why)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         perror(why);
  58         error_count++;
  59 }
  60 
  61 static char *randbuf(int len)
     /* [<][>][^][v][top][bottom][index][help] */
  62 {
  63         char *buf;
  64         int i;
  65         buf = (char *)malloc(len+1);
  66 
  67         for (i=0;i<len;i++) {
  68                 buf[i] = 'a' + (rand() % 26);
  69         }
  70         buf[i] = 0;
  71         return buf;
  72 }
  73 
  74 static int cull_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
  75                          void *state)
  76 {
  77 #if CULL_PROB
  78         if (random() % CULL_PROB == 0) {
  79                 tdb_delete(tdb, key);
  80         }
  81 #endif
  82         return 0;
  83 }
  84 
  85 static void addrec_db(void)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87         int klen, dlen;
  88         char *k, *d;
  89         TDB_DATA key, data;
  90 
  91         klen = 1 + (rand() % KEYLEN);
  92         dlen = 1 + (rand() % DATALEN);
  93 
  94         k = randbuf(klen);
  95         d = randbuf(dlen);
  96 
  97         key.dptr = (unsigned char *)k;
  98         key.dsize = klen+1;
  99 
 100         data.dptr = (unsigned char *)d;
 101         data.dsize = dlen+1;
 102 
 103 #if TRANSACTION_PROB
 104         if (in_transaction == 0 && random() % TRANSACTION_PROB == 0) {
 105                 if (tdb_transaction_start(db) != 0) {
 106                         fatal("tdb_transaction_start failed");
 107                 }
 108                 in_transaction++;
 109                 goto next;
 110         }
 111         if (in_transaction && random() % TRANSACTION_PROB == 0) {
 112                 if (tdb_transaction_commit(db) != 0) {
 113                         fatal("tdb_transaction_commit failed");
 114                 }
 115                 in_transaction--;
 116                 goto next;
 117         }
 118         if (in_transaction && random() % TRANSACTION_PROB == 0) {
 119                 if (tdb_transaction_cancel(db) != 0) {
 120                         fatal("tdb_transaction_cancel failed");
 121                 }
 122                 in_transaction--;
 123                 goto next;
 124         }
 125 #endif
 126 
 127 #if REOPEN_PROB
 128         if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
 129                 tdb_reopen_all(0);
 130                 goto next;
 131         } 
 132 #endif
 133 
 134 #if DELETE_PROB
 135         if (random() % DELETE_PROB == 0) {
 136                 tdb_delete(db, key);
 137                 goto next;
 138         }
 139 #endif
 140 
 141 #if STORE_PROB
 142         if (random() % STORE_PROB == 0) {
 143                 if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
 144                         fatal("tdb_store failed");
 145                 }
 146                 goto next;
 147         }
 148 #endif
 149 
 150 #if APPEND_PROB
 151         if (random() % APPEND_PROB == 0) {
 152                 if (tdb_append(db, key, data) != 0) {
 153                         fatal("tdb_append failed");
 154                 }
 155                 goto next;
 156         }
 157 #endif
 158 
 159 #if LOCKSTORE_PROB
 160         if (random() % LOCKSTORE_PROB == 0) {
 161                 tdb_chainlock(db, key);
 162                 data = tdb_fetch(db, key);
 163                 if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
 164                         fatal("tdb_store failed");
 165                 }
 166                 if (data.dptr) free(data.dptr);
 167                 tdb_chainunlock(db, key);
 168                 goto next;
 169         } 
 170 #endif
 171 
 172 #if TRAVERSE_PROB
 173         if (random() % TRAVERSE_PROB == 0) {
 174                 tdb_traverse(db, cull_traverse, NULL);
 175                 goto next;
 176         }
 177 #endif
 178 
 179 #if TRAVERSE_READ_PROB
 180         if (random() % TRAVERSE_READ_PROB == 0) {
 181                 tdb_traverse_read(db, NULL, NULL);
 182                 goto next;
 183         }
 184 #endif
 185 
 186         data = tdb_fetch(db, key);
 187         if (data.dptr) free(data.dptr);
 188 
 189 next:
 190         free(k);
 191         free(d);
 192 }
 193 
 194 static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
 195                        void *state)
 196 {
 197         tdb_delete(tdb, key);
 198         return 0;
 199 }
 200 
 201 static void usage(void)
     /* [<][>][^][v][top][bottom][index][help] */
 202 {
 203         printf("Usage: tdbtorture [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
 204         exit(0);
 205 }
 206 
 207  int main(int argc, char * const *argv)
     /* [<][>][^][v][top][bottom][index][help] */
 208 {
 209         int i, seed = -1;
 210         int num_procs = 3;
 211         int num_loops = 5000;
 212         int hash_size = 2;
 213         int c;
 214         extern char *optarg;
 215         pid_t *pids;
 216 
 217         struct tdb_logging_context log_ctx;
 218         log_ctx.log_fn = tdb_log;
 219 
 220         while ((c = getopt(argc, argv, "n:l:s:H:h")) != -1) {
 221                 switch (c) {
 222                 case 'n':
 223                         num_procs = strtol(optarg, NULL, 0);
 224                         break;
 225                 case 'l':
 226                         num_loops = strtol(optarg, NULL, 0);
 227                         break;
 228                 case 'H':
 229                         hash_size = strtol(optarg, NULL, 0);
 230                         break;
 231                 case 's':
 232                         seed = strtol(optarg, NULL, 0);
 233                         break;
 234                 default:
 235                         usage();
 236                 }
 237         }
 238 
 239         unlink("torture.tdb");
 240 
 241         pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
 242         pids[0] = getpid();
 243 
 244         for (i=0;i<num_procs-1;i++) {
 245                 if ((pids[i+1]=fork()) == 0) break;
 246         }
 247 
 248         db = tdb_open_ex("torture.tdb", hash_size, TDB_CLEAR_IF_FIRST, 
 249                          O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
 250         if (!db) {
 251                 fatal("db open failed");
 252         }
 253 
 254         if (seed == -1) {
 255                 seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
 256         }
 257 
 258         if (i == 0) {
 259                 printf("testing with %d processes, %d loops, %d hash_size, seed=%d\n", 
 260                        num_procs, num_loops, hash_size, seed);
 261         }
 262 
 263         srand(seed + i);
 264         srandom(seed + i);
 265 
 266         for (i=0;i<num_loops && error_count == 0;i++) {
 267                 addrec_db();
 268         }
 269 
 270         if (error_count == 0) {
 271                 tdb_traverse_read(db, NULL, NULL);
 272                 tdb_traverse(db, traverse_fn, NULL);
 273                 tdb_traverse(db, traverse_fn, NULL);
 274         }
 275 
 276         tdb_close(db);
 277 
 278         if (getpid() != pids[0]) {
 279                 return error_count;
 280         }
 281 
 282         for (i=1;i<num_procs;i++) {
 283                 int status, j;
 284                 pid_t pid;
 285                 if (error_count != 0) {
 286                         /* try and stop the test on any failure */
 287                         for (j=1;j<num_procs;j++) {
 288                                 if (pids[j] != 0) {
 289                                         kill(pids[j], SIGTERM);
 290                                 }
 291                         }
 292                 }
 293                 pid = waitpid(-1, &status, 0);
 294                 if (pid == -1) {
 295                         perror("failed to wait for child\n");
 296                         exit(1);
 297                 }
 298                 for (j=1;j<num_procs;j++) {
 299                         if (pids[j] == pid) break;
 300                 }
 301                 if (j == num_procs) {
 302                         printf("unknown child %d exited!?\n", (int)pid);
 303                         exit(1);
 304                 }
 305                 if (WEXITSTATUS(status) != 0) {
 306                         printf("child %d exited with status %d\n",
 307                                (int)pid, WEXITSTATUS(status));
 308                         error_count++;
 309                 }
 310                 pids[j] = 0;
 311         }
 312 
 313         if (error_count == 0) {
 314                 printf("OK\n");
 315         }
 316 
 317         return error_count;
 318 }

/* [<][>][^][v][top][bottom][index][help] */