1#include <stdlib.h> 2#include <time.h> 3#include <stdio.h> 4#include <fcntl.h> 5#include <unistd.h> 6#include <string.h> 7#include <fcntl.h> 8#include <signal.h> 9#include <stdarg.h> 10#include <sys/mman.h> 11#include <sys/stat.h> 12#include <sys/time.h> 13#include <sys/wait.h> 14#include "tdb.h" 15 16/* this tests tdb by doing lots of ops from several simultaneous 17 writers - that stresses the locking code. Build with TDB_DEBUG=1 18 for best effect */ 19 20 21 22#define REOPEN_PROB 30 23#define DELETE_PROB 8 24#define STORE_PROB 4 25#define APPEND_PROB 6 26#define LOCKSTORE_PROB 0 27#define TRAVERSE_PROB 20 28#define CULL_PROB 100 29#define KEYLEN 3 30#define DATALEN 100 31#define LOCKLEN 20 32 33static TDB_CONTEXT *db; 34 35static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...) 36{ 37 va_list ap; 38 39 va_start(ap, format); 40 vfprintf(stdout, format, ap); 41 va_end(ap); 42 fflush(stdout); 43#if 0 44 { 45 char *ptr; 46 asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid()); 47 system(ptr); 48 free(ptr); 49 } 50#endif 51} 52 53static void fatal(char *why) 54{ 55 perror(why); 56 exit(1); 57} 58 59static char *randbuf(int len) 60{ 61 char *buf; 62 int i; 63 buf = (char *)malloc(len+1); 64 65 for (i=0;i<len;i++) { 66 buf[i] = 'a' + (rand() % 26); 67 } 68 buf[i] = 0; 69 return buf; 70} 71 72static int cull_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, 73 void *state) 74{ 75 if (random() % CULL_PROB == 0) { 76 tdb_delete(tdb, key); 77 } 78 return 0; 79} 80 81static void addrec_db(void) 82{ 83 int klen, dlen, slen; 84 char *k, *d, *s; 85 TDB_DATA key, data, lockkey; 86 87 klen = 1 + (rand() % KEYLEN); 88 dlen = 1 + (rand() % DATALEN); 89 slen = 1 + (rand() % LOCKLEN); 90 91 k = randbuf(klen); 92 d = randbuf(dlen); 93 s = randbuf(slen); 94 95 key.dptr = k; 96 key.dsize = klen+1; 97 98 data.dptr = d; 99 data.dsize = dlen+1; 100 101 lockkey.dptr = s; 102 lockkey.dsize = slen+1; 103 104#if REOPEN_PROB 105 if (random() % REOPEN_PROB == 0) { 106 tdb_reopen_all(); 107 goto next; 108 } 109#endif 110 111#if DELETE_PROB 112 if (random() % DELETE_PROB == 0) { 113 tdb_delete(db, key); 114 goto next; 115 } 116#endif 117 118#if STORE_PROB 119 if (random() % STORE_PROB == 0) { 120 if (tdb_store(db, key, data, TDB_REPLACE) != 0) { 121 fatal("tdb_store failed"); 122 } 123 goto next; 124 } 125#endif 126 127#if APPEND_PROB 128 if (random() % APPEND_PROB == 0) { 129 if (tdb_append(db, key, data) != 0) { 130 fatal("tdb_append failed"); 131 } 132 goto next; 133 } 134#endif 135 136#if LOCKSTORE_PROB 137 if (random() % LOCKSTORE_PROB == 0) { 138 tdb_chainlock(db, lockkey); 139 data = tdb_fetch(db, key); 140 if (tdb_store(db, key, data, TDB_REPLACE) != 0) { 141 fatal("tdb_store failed"); 142 } 143 if (data.dptr) free(data.dptr); 144 tdb_chainunlock(db, lockkey); 145 goto next; 146 } 147#endif 148 149#if TRAVERSE_PROB 150 if (random() % TRAVERSE_PROB == 0) { 151 tdb_traverse(db, cull_traverse, NULL); 152 goto next; 153 } 154#endif 155 156 data = tdb_fetch(db, key); 157 if (data.dptr) free(data.dptr); 158 159next: 160 free(k); 161 free(d); 162 free(s); 163} 164 165static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, 166 void *state) 167{ 168 tdb_delete(tdb, key); 169 return 0; 170} 171 172#ifndef NPROC 173#define NPROC 6 174#endif 175 176#ifndef NLOOPS 177#define NLOOPS 200000 178#endif 179 180int main(int argc, char *argv[]) 181{ 182 int i, seed=0; 183 int loops = NLOOPS; 184 pid_t pids[NPROC]; 185 186 pids[0] = getpid(); 187 188 for (i=0;i<NPROC-1;i++) { 189 if ((pids[i+1]=fork()) == 0) break; 190 } 191 192 db = tdb_open("torture.tdb", 2, TDB_CLEAR_IF_FIRST, 193 O_RDWR | O_CREAT, 0600); 194 if (!db) { 195 fatal("db open failed"); 196 } 197 tdb_logging_function(db, tdb_log); 198 199 srand(seed + getpid()); 200 srandom(seed + getpid() + time(NULL)); 201 for (i=0;i<loops;i++) addrec_db(); 202 203 tdb_traverse(db, NULL, NULL); 204 tdb_traverse(db, traverse_fn, NULL); 205 tdb_traverse(db, traverse_fn, NULL); 206 207 tdb_close(db); 208 209 if (getpid() == pids[0]) { 210 for (i=0;i<NPROC-1;i++) { 211 int status; 212 if (waitpid(pids[i+1], &status, 0) != pids[i+1]) { 213 printf("failed to wait for %d\n", 214 (int)pids[i+1]); 215 exit(1); 216 } 217 if (WEXITSTATUS(status) != 0) { 218 printf("child %d exited with status %d\n", 219 (int)pids[i+1], WEXITSTATUS(status)); 220 exit(1); 221 } 222 } 223 printf("OK\n"); 224 } 225 226 return 0; 227} 228