~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to lib/tdb/tools/tdbtorture.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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);
 
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)
 
56
{
 
57
        perror(why);
 
58
        error_count++;
 
59
}
 
60
 
 
61
static char *randbuf(int len)
 
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,
 
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)
 
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,
 
195
                       void *state)
 
196
{
 
197
        tdb_delete(tdb, key);
 
198
        return 0;
 
199
}
 
200
 
 
201
static void usage(void)
 
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)
 
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
}