/* ** 2010-07-22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** The code in this file runs a few multi-threaded test cases using the ** SQLite library. It can be compiled to an executable on unix using the ** following command: ** ** gcc -O2 threadtest3.c sqlite3.c -ldl -lpthread -lm ** ** Even though threadtest3.c is the only C source code file mentioned on ** the compiler command-line, #include macros are used to pull in additional ** C code files named "tt3_*.c". ** ** After compiling, run this program with an optional argument telling ** which test to run. All tests are run if no argument is given. The ** argument can be a glob pattern to match multiple tests. Examples: ** ** ./a.out -- Run all tests ** ./a.out walthread3 -- Run the "walthread3" test ** ./a.out 'wal*' -- Run all of the wal* tests ** ./a.out --help -- List all available tests ** ** The exit status is non-zero if any test fails. */ #include #include "test_multiplex.h" #include "tt3_core.c" /* Required to link test_multiplex.c */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif /************************************************************************* ************************************************************************** ************************************************************************** ** End infrastructure. Begin tests. */ #define WALTHREAD1_NTHREAD 10 #define WALTHREAD3_NTHREAD 6 static char *walthread1_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nIter = 0; /* Iterations so far */ opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ const char *azSql[] = { "SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1)", "SELECT x FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)", }; char *z1, *z2, *z3; execsql(&err, &db, "BEGIN"); integrity_check(&err, &db); z1 = execsql_text(&err, &db, 1, azSql[0]); z2 = execsql_text(&err, &db, 2, azSql[1]); z3 = execsql_text(&err, &db, 3, azSql[0]); execsql(&err, &db, "COMMIT"); if( strcmp(z1, z2) || strcmp(z1, z3) ){ test_error(&err, "Failed read: %s %s %s", z1, z2, z3); } sql_script(&err, &db, "BEGIN;" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 SELECT md5sum(x) FROM t1;" "COMMIT;" ); nIter++; } closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("%d iterations", nIter); } static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ usleep(500*1000); execsql(&err, &db, "PRAGMA wal_checkpoint"); if( err.rc==SQLITE_OK ) nCkpt++; clear_error(&err, SQLITE_BUSY); } closedb(&err, &db); print_and_free_err(&err); return sqlite3_mprintf("%d checkpoints", nCkpt); } static void walthread1(int nMs){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ Threadset threads = {0}; /* Test threads */ int i; /* Iterator variable */ opendb(&err, &db, "test.db", 1); sql_script(&err, &db, "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(x PRIMARY KEY);" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 VALUES(randomblob(100));" "INSERT INTO t1 SELECT md5sum(x) FROM t1;" ); closedb(&err, &db); setstoptime(&err, nMs); for(i=0; i= 0); wal_exists = (filesize(&err, "test.db-wal") >= 0); if( (journal_exists+wal_exists)!=1 ){ test_error(&err, "File system looks incorrect (%d, %d)", journal_exists, wal_exists ); } anTrans[journal_exists]++; sql_script(&err, &db, "COMMIT"); integrity_check(&err, &db); closedb(&err, &db); } print_and_free_err(&err); return sqlite3_mprintf("W %d R %d", anTrans[0], anTrans[1]); } static void walthread2(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; opendb(&err, &db, "test.db", 1); sql_script(&err, &db, "CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE)"); closedb(&err, &db); setstoptime(&err, nMs); launch_thread(&err, &threads, walthread2_thread, 0); launch_thread(&err, &threads, walthread2_thread, 0); launch_thread(&err, &threads, walthread2_thread, (void*)1); launch_thread(&err, &threads, walthread2_thread, (void*)1); join_all_threads(&err, &threads); print_and_free_err(&err); } static char *walthread3_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 iNextWrite; /* Next value this thread will write */ int iArg = PTR2INT(pArg); opendb(&err, &db, "test.db", 0); sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10"); iNextWrite = iArg+1; while( 1 ){ i64 sum1; i64 sum2; int stop = 0; /* True to stop executing (test timed out) */ while( 0==(stop = timetostop(&err)) ){ i64 iMax = execsql_i64(&err, &db, "SELECT max(cnt) FROM t1"); if( iMax+1==iNextWrite ) break; } if( stop ) break; sum1 = execsql_i64(&err, &db, "SELECT sum(cnt) FROM t1"); sum2 = execsql_i64(&err, &db, "SELECT sum(sum1) FROM t1"); execsql_i64(&err, &db, "INSERT INTO t1 VALUES(:iNextWrite, :iSum1, :iSum2)", &iNextWrite, &sum1, &sum2 ); integrity_check(&err, &db); iNextWrite += WALTHREAD3_NTHREAD; } closedb(&err, &db); print_and_free_err(&err); return 0; } static void walthread3(int nMs){ Error err = {0}; Sqlite db = {0}; Threadset threads = {0}; int i; opendb(&err, &db, "test.db", 1); sql_script(&err, &db, "PRAGMA journal_mode = WAL;" "CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);" "CREATE INDEX i1 ON t1(sum1);" "CREATE INDEX i2 ON t1(sum2);" "INSERT INTO t1 VALUES(0, 0, 0);" ); closedb(&err, &db); setstoptime(&err, nMs); for(i=0; i=sizeof(aTest)/sizeof(aTest[0]) ) goto usage; } for(iArg=1; iArg0 ? 255 : 0); usage: printf("Usage: %s [-multiplexor] [testname|testprefix*]...\n", argv[0]); printf("Available tests are:\n"); for(i=0; i