1
/* this tests tdb by doing lots of ops from several simultaneous
2
writers - that stresses the locking code.
6
#include "system/time.h"
7
#include "system/wait.h"
8
#include "system/filesys.h"
16
#define REOPEN_PROB 30
20
#define TRANSACTION_PROB 10
21
#define LOCKSTORE_PROB 5
22
#define TRAVERSE_PROB 20
23
#define TRAVERSE_READ_PROB 20
28
static struct tdb_context *db;
29
static int in_transaction;
30
static int error_count;
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);
35
static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
42
vfprintf(stdout, format, ap);
48
asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
55
static void fatal(const char *why)
61
static char *randbuf(int len)
65
buf = (char *)malloc(len+1);
68
buf[i] = 'a' + (rand() % 26);
74
static int cull_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
78
if (random() % CULL_PROB == 0) {
85
static void addrec_db(void)
91
klen = 1 + (rand() % KEYLEN);
92
dlen = 1 + (rand() % DATALEN);
97
key.dptr = (unsigned char *)k;
100
data.dptr = (unsigned char *)d;
104
if (in_transaction == 0 && random() % TRANSACTION_PROB == 0) {
105
if (tdb_transaction_start(db) != 0) {
106
fatal("tdb_transaction_start failed");
111
if (in_transaction && random() % TRANSACTION_PROB == 0) {
112
if (tdb_transaction_commit(db) != 0) {
113
fatal("tdb_transaction_commit failed");
118
if (in_transaction && random() % TRANSACTION_PROB == 0) {
119
if (tdb_transaction_cancel(db) != 0) {
120
fatal("tdb_transaction_cancel failed");
128
if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
135
if (random() % DELETE_PROB == 0) {
142
if (random() % STORE_PROB == 0) {
143
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
144
fatal("tdb_store failed");
151
if (random() % APPEND_PROB == 0) {
152
if (tdb_append(db, key, data) != 0) {
153
fatal("tdb_append failed");
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");
166
if (data.dptr) free(data.dptr);
167
tdb_chainunlock(db, key);
173
if (random() % TRAVERSE_PROB == 0) {
174
tdb_traverse(db, cull_traverse, NULL);
179
#if TRAVERSE_READ_PROB
180
if (random() % TRAVERSE_READ_PROB == 0) {
181
tdb_traverse_read(db, NULL, NULL);
186
data = tdb_fetch(db, key);
187
if (data.dptr) free(data.dptr);
194
static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
197
tdb_delete(tdb, key);
201
static void usage(void)
203
printf("Usage: tdbtorture [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
207
int main(int argc, char * const *argv)
211
int num_loops = 5000;
217
struct tdb_logging_context log_ctx;
218
log_ctx.log_fn = tdb_log;
220
while ((c = getopt(argc, argv, "n:l:s:H:h")) != -1) {
223
num_procs = strtol(optarg, NULL, 0);
226
num_loops = strtol(optarg, NULL, 0);
229
hash_size = strtol(optarg, NULL, 0);
232
seed = strtol(optarg, NULL, 0);
239
unlink("torture.tdb");
241
pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
244
for (i=0;i<num_procs-1;i++) {
245
if ((pids[i+1]=fork()) == 0) break;
248
db = tdb_open_ex("torture.tdb", hash_size, TDB_CLEAR_IF_FIRST,
249
O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
251
fatal("db open failed");
255
seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
259
printf("testing with %d processes, %d loops, %d hash_size, seed=%d\n",
260
num_procs, num_loops, hash_size, seed);
266
for (i=0;i<num_loops && error_count == 0;i++) {
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);
278
if (getpid() != pids[0]) {
282
for (i=1;i<num_procs;i++) {
285
if (error_count != 0) {
286
/* try and stop the test on any failure */
287
for (j=1;j<num_procs;j++) {
289
kill(pids[j], SIGTERM);
293
pid = waitpid(-1, &status, 0);
295
perror("failed to wait for child\n");
298
for (j=1;j<num_procs;j++) {
299
if (pids[j] == pid) break;
301
if (j == num_procs) {
302
printf("unknown child %d exited!?\n", (int)pid);
305
if (WEXITSTATUS(status) != 0) {
306
printf("child %d exited with status %d\n",
307
(int)pid, WEXITSTATUS(status));
313
if (error_count == 0) {