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