1999-12-24 11:46:02 +03:00
# include <stdlib.h>
2001-12-04 16:17:22 +03:00
# include <time.h>
1999-12-24 11:46:02 +03:00
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <fcntl.h>
2003-10-18 12:52:16 +04:00
# include <signal.h>
2001-05-28 17:29:06 +04:00
# include <stdarg.h>
1999-12-24 11:46:02 +03:00
# include <sys/mman.h>
# include <sys/stat.h>
# include <sys/time.h>
2001-05-30 09:40:52 +04:00
# include <sys/wait.h>
1999-12-24 11:46:02 +03:00
# include "tdb.h"
/* this tests tdb by doing lots of ops from several simultaneous
writers - that stresses the locking code . Build with TDB_DEBUG = 1
for best effect */
2001-09-24 08:56:56 +04:00
# define REOPEN_PROB 30
# define DELETE_PROB 8
# define STORE_PROB 4
2003-01-11 03:07:44 +03:00
# define APPEND_PROB 6
2001-09-24 08:56:56 +04:00
# define LOCKSTORE_PROB 0
# define TRAVERSE_PROB 20
# define CULL_PROB 100
1999-12-24 11:46:02 +03:00
# define KEYLEN 3
# define DATALEN 100
2001-09-24 08:56:56 +04:00
# define LOCKLEN 20
1999-12-24 11:46:02 +03:00
static TDB_CONTEXT * db ;
2001-05-28 17:29:06 +04:00
static void tdb_log ( TDB_CONTEXT * tdb , int level , const char * format , . . . )
{
va_list ap ;
va_start ( ap , format ) ;
vfprintf ( stdout , format , ap ) ;
va_end ( ap ) ;
2001-09-06 09:59:32 +04:00
fflush ( stdout ) ;
2001-05-30 09:40:52 +04:00
#if 0
{
char * ptr ;
asprintf ( & ptr , " xterm -e gdb /proc/%d/exe %d " , getpid ( ) , getpid ( ) ) ;
system ( ptr ) ;
free ( ptr ) ;
}
# endif
2001-05-28 17:29:06 +04:00
}
1999-12-24 11:46:02 +03:00
static void fatal ( char * why )
{
perror ( why ) ;
exit ( 1 ) ;
}
static char * randbuf ( int len )
{
char * buf ;
int i ;
buf = ( char * ) malloc ( len + 1 ) ;
for ( i = 0 ; i < len ; i + + ) {
buf [ i ] = ' a ' + ( rand ( ) % 26 ) ;
}
buf [ i ] = 0 ;
return buf ;
}
2001-12-11 11:31:58 +03:00
static int cull_traverse ( TDB_CONTEXT * tdb , TDB_DATA key , TDB_DATA dbuf ,
2001-05-30 09:40:52 +04:00
void * state )
{
if ( random ( ) % CULL_PROB = = 0 ) {
2001-12-11 11:31:58 +03:00
tdb_delete ( tdb , key ) ;
2001-05-30 09:40:52 +04:00
}
return 0 ;
}
1999-12-24 11:46:02 +03:00
static void addrec_db ( void )
{
2001-09-24 08:56:56 +04:00
int klen , dlen , slen ;
char * k , * d , * s ;
TDB_DATA key , data , lockkey ;
1999-12-24 11:46:02 +03:00
klen = 1 + ( rand ( ) % KEYLEN ) ;
dlen = 1 + ( rand ( ) % DATALEN ) ;
2001-09-24 08:56:56 +04:00
slen = 1 + ( rand ( ) % LOCKLEN ) ;
1999-12-24 11:46:02 +03:00
k = randbuf ( klen ) ;
d = randbuf ( dlen ) ;
2001-09-24 08:56:56 +04:00
s = randbuf ( slen ) ;
1999-12-24 11:46:02 +03:00
key . dptr = k ;
key . dsize = klen + 1 ;
data . dptr = d ;
data . dsize = dlen + 1 ;
2001-09-24 08:56:56 +04:00
lockkey . dptr = s ;
lockkey . dsize = slen + 1 ;
# if REOPEN_PROB
if ( random ( ) % REOPEN_PROB = = 0 ) {
tdb_reopen_all ( ) ;
goto next ;
}
# endif
# if DELETE_PROB
2001-05-30 09:40:52 +04:00
if ( random ( ) % DELETE_PROB = = 0 ) {
1999-12-24 11:46:02 +03:00
tdb_delete ( db , key ) ;
2001-09-27 05:57:02 +04:00
goto next ;
2001-09-24 08:56:56 +04:00
}
# endif
# if STORE_PROB
if ( random ( ) % STORE_PROB = = 0 ) {
1999-12-24 11:46:02 +03:00
if ( tdb_store ( db , key , data , TDB_REPLACE ) ! = 0 ) {
fatal ( " tdb_store failed " ) ;
}
2001-09-27 05:57:02 +04:00
goto next ;
2001-09-24 08:56:56 +04:00
}
# endif
2003-01-11 03:07:44 +03:00
# if APPEND_PROB
if ( random ( ) % APPEND_PROB = = 0 ) {
if ( tdb_append ( db , key , data ) ! = 0 ) {
fatal ( " tdb_append failed " ) ;
}
goto next ;
}
# endif
2001-09-24 08:56:56 +04:00
# if LOCKSTORE_PROB
if ( random ( ) % LOCKSTORE_PROB = = 0 ) {
tdb_chainlock ( db , lockkey ) ;
1999-12-24 11:46:02 +03:00
data = tdb_fetch ( db , key ) ;
2001-09-24 08:56:56 +04:00
if ( tdb_store ( db , key , data , TDB_REPLACE ) ! = 0 ) {
fatal ( " tdb_store failed " ) ;
}
1999-12-24 11:46:02 +03:00
if ( data . dptr ) free ( data . dptr ) ;
2001-09-24 08:56:56 +04:00
tdb_chainunlock ( db , lockkey ) ;
2001-09-27 05:57:02 +04:00
goto next ;
2001-09-24 08:56:56 +04:00
}
# endif
# if TRAVERSE_PROB
if ( random ( ) % TRAVERSE_PROB = = 0 ) {
tdb_traverse ( db , cull_traverse , NULL ) ;
2001-09-27 05:57:02 +04:00
goto next ;
1999-12-24 11:46:02 +03:00
}
2001-09-24 08:56:56 +04:00
# endif
data = tdb_fetch ( db , key ) ;
if ( data . dptr ) free ( data . dptr ) ;
1999-12-24 11:46:02 +03:00
2001-09-27 05:57:02 +04:00
next :
1999-12-24 11:46:02 +03:00
free ( k ) ;
free ( d ) ;
2001-09-24 08:56:56 +04:00
free ( s ) ;
1999-12-24 11:46:02 +03:00
}
2001-12-11 11:31:58 +03:00
static int traverse_fn ( TDB_CONTEXT * tdb , TDB_DATA key , TDB_DATA dbuf ,
2000-02-28 03:37:13 +03:00
void * state )
1999-12-24 11:46:02 +03:00
{
2001-12-11 11:31:58 +03:00
tdb_delete ( tdb , key ) ;
1999-12-24 11:46:02 +03:00
return 0 ;
}
# ifndef NPROC
2001-05-30 09:40:52 +04:00
# define NPROC 6
1999-12-24 11:46:02 +03:00
# endif
# ifndef NLOOPS
2001-05-30 09:40:52 +04:00
# define NLOOPS 200000
1999-12-24 11:46:02 +03:00
# endif
int main ( int argc , char * argv [ ] )
{
int i , seed = 0 ;
int loops = NLOOPS ;
2001-05-30 09:40:52 +04:00
pid_t pids [ NPROC ] ;
pids [ 0 ] = getpid ( ) ;
1999-12-24 11:46:02 +03:00
for ( i = 0 ; i < NPROC - 1 ; i + + ) {
2001-05-30 09:40:52 +04:00
if ( ( pids [ i + 1 ] = fork ( ) ) = = 0 ) break ;
1999-12-24 11:46:02 +03:00
}
2001-12-04 14:41:12 +03:00
db = tdb_open ( " torture.tdb " , 2 , TDB_CLEAR_IF_FIRST ,
O_RDWR | O_CREAT , 0600 ) ;
1999-12-24 11:46:02 +03:00
if ( ! db ) {
fatal ( " db open failed " ) ;
}
2001-05-28 17:29:06 +04:00
tdb_logging_function ( db , tdb_log ) ;
1999-12-24 11:46:02 +03:00
srand ( seed + getpid ( ) ) ;
2001-05-30 09:40:52 +04:00
srandom ( seed + getpid ( ) + time ( NULL ) ) ;
1999-12-24 11:46:02 +03:00
for ( i = 0 ; i < loops ; i + + ) addrec_db ( ) ;
2001-05-30 09:40:52 +04:00
tdb_traverse ( db , NULL , NULL ) ;
tdb_traverse ( db , traverse_fn , NULL ) ;
tdb_traverse ( db , traverse_fn , NULL ) ;
1999-12-24 11:46:02 +03:00
tdb_close ( db ) ;
2001-05-30 09:40:52 +04:00
if ( getpid ( ) = = pids [ 0 ] ) {
for ( i = 0 ; i < NPROC - 1 ; i + + ) {
int status ;
if ( waitpid ( pids [ i + 1 ] , & status , 0 ) ! = pids [ i + 1 ] ) {
printf ( " failed to wait for %d \n " ,
( int ) pids [ i + 1 ] ) ;
exit ( 1 ) ;
}
if ( WEXITSTATUS ( status ) ! = 0 ) {
printf ( " child %d exited with status %d \n " ,
( int ) pids [ i + 1 ] , WEXITSTATUS ( status ) ) ;
exit ( 1 ) ;
}
}
printf ( " OK \n " ) ;
}
1999-12-24 11:46:02 +03:00
return 0 ;
}