17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate ** 2004 January 13
37c478bd9Sstevel@tonic-gate **
47c478bd9Sstevel@tonic-gate ** The author disclaims copyright to this source code.  In place of
57c478bd9Sstevel@tonic-gate ** a legal notice, here is a blessing:
67c478bd9Sstevel@tonic-gate **
77c478bd9Sstevel@tonic-gate **    May you do good and not evil.
87c478bd9Sstevel@tonic-gate **    May you find forgiveness for yourself and forgive others.
97c478bd9Sstevel@tonic-gate **    May you share freely, never taking more than you give.
107c478bd9Sstevel@tonic-gate **
117c478bd9Sstevel@tonic-gate *************************************************************************
127c478bd9Sstevel@tonic-gate ** This file implements a simple standalone program used to test whether
137c478bd9Sstevel@tonic-gate ** or not the SQLite library is threadsafe.
147c478bd9Sstevel@tonic-gate **
157c478bd9Sstevel@tonic-gate ** This file is NOT part of the standard SQLite library.  It is used for
167c478bd9Sstevel@tonic-gate ** testing only.
177c478bd9Sstevel@tonic-gate */
187c478bd9Sstevel@tonic-gate #include <stdio.h>
197c478bd9Sstevel@tonic-gate #include <unistd.h>
207c478bd9Sstevel@tonic-gate #include <pthread.h>
217c478bd9Sstevel@tonic-gate #include <string.h>
227c478bd9Sstevel@tonic-gate #include <stdlib.h>
237c478bd9Sstevel@tonic-gate #include "sqlite.h"
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate ** Name of the database
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate #define DB_FILE "test.db"
297c478bd9Sstevel@tonic-gate 
30*1da57d55SToomas Soome /*
317c478bd9Sstevel@tonic-gate ** When this variable becomes non-zero, all threads stop
327c478bd9Sstevel@tonic-gate ** what they are doing.
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate volatile int all_stop = 0;
357c478bd9Sstevel@tonic-gate 
36*1da57d55SToomas Soome /*
377c478bd9Sstevel@tonic-gate ** Callback from the integrity check.  If the result is anything other
387c478bd9Sstevel@tonic-gate ** than "ok" it means the integrity check has failed.  Set the "all_stop"
397c478bd9Sstevel@tonic-gate ** global variable to stop all other activity.  Print the error message
407c478bd9Sstevel@tonic-gate ** or print OK if the string "ok" is seen.
417c478bd9Sstevel@tonic-gate */
check_callback(void * notUsed,int argc,char ** argv,char ** notUsed2)427c478bd9Sstevel@tonic-gate int check_callback(void *notUsed, int argc, char **argv, char **notUsed2){
437c478bd9Sstevel@tonic-gate   if( strcmp(argv[0],"ok") ){
447c478bd9Sstevel@tonic-gate     all_stop = 1;
457c478bd9Sstevel@tonic-gate     fprintf(stderr,"pid=%d. %s\n", getpid(), argv[0]);
467c478bd9Sstevel@tonic-gate   }else{
477c478bd9Sstevel@tonic-gate     /* fprintf(stderr,"pid=%d. OK\n", getpid()); */
487c478bd9Sstevel@tonic-gate   }
497c478bd9Sstevel@tonic-gate   return 0;
507c478bd9Sstevel@tonic-gate }
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate ** Do an integrity check on the database.  If the first integrity check
547c478bd9Sstevel@tonic-gate ** fails, try it a second time.
557c478bd9Sstevel@tonic-gate */
integrity_check(sqlite * db)567c478bd9Sstevel@tonic-gate int integrity_check(sqlite *db){
577c478bd9Sstevel@tonic-gate   int rc;
587c478bd9Sstevel@tonic-gate   if( all_stop ) return 0;
597c478bd9Sstevel@tonic-gate   /* fprintf(stderr,"pid=%d: CHECK\n", getpid()); */
607c478bd9Sstevel@tonic-gate   rc = sqlite_exec(db, "pragma integrity_check", check_callback, 0, 0);
617c478bd9Sstevel@tonic-gate   if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
627c478bd9Sstevel@tonic-gate     fprintf(stderr,"pid=%d, Integrity check returns %d\n", getpid(), rc);
637c478bd9Sstevel@tonic-gate   }
647c478bd9Sstevel@tonic-gate   if( all_stop ){
657c478bd9Sstevel@tonic-gate     sqlite_exec(db, "pragma integrity_check", check_callback, 0, 0);
667c478bd9Sstevel@tonic-gate   }
677c478bd9Sstevel@tonic-gate   return 0;
687c478bd9Sstevel@tonic-gate }
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate ** This is the worker thread
727c478bd9Sstevel@tonic-gate */
worker(void * notUsed)737c478bd9Sstevel@tonic-gate void *worker(void *notUsed){
747c478bd9Sstevel@tonic-gate   sqlite *db;
757c478bd9Sstevel@tonic-gate   int rc;
767c478bd9Sstevel@tonic-gate   int cnt = 0;
777c478bd9Sstevel@tonic-gate   while( !all_stop && cnt++<10000 ){
787c478bd9Sstevel@tonic-gate     if( cnt%1000==0 ) printf("pid=%d: %d\n", getpid(), cnt);
797c478bd9Sstevel@tonic-gate     while( (db = sqlite_open(DB_FILE, 0, 0))==0 ) sched_yield();
807c478bd9Sstevel@tonic-gate     sqlite_exec(db, "PRAGMA synchronous=OFF", 0, 0, 0);
817c478bd9Sstevel@tonic-gate     integrity_check(db);
827c478bd9Sstevel@tonic-gate     if( all_stop ){ sqlite_close(db); break; }
837c478bd9Sstevel@tonic-gate     /* fprintf(stderr, "pid=%d: BEGIN\n", getpid()); */
847c478bd9Sstevel@tonic-gate     rc = sqlite_exec(db, "INSERT INTO t1 VALUES('bogus data')", 0, 0, 0);
857c478bd9Sstevel@tonic-gate     /* fprintf(stderr, "pid=%d: END rc=%d\n", getpid(), rc); */
867c478bd9Sstevel@tonic-gate     sqlite_close(db);
877c478bd9Sstevel@tonic-gate   }
887c478bd9Sstevel@tonic-gate   return 0;
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate ** Initialize the database and start the threads
937c478bd9Sstevel@tonic-gate */
main(int argc,char ** argv)947c478bd9Sstevel@tonic-gate int main(int argc, char **argv){
957c478bd9Sstevel@tonic-gate   sqlite *db;
967c478bd9Sstevel@tonic-gate   int i, rc;
977c478bd9Sstevel@tonic-gate   pthread_t aThread[5];
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate   if( strcmp(DB_FILE,":memory:") ) unlink(DB_FILE);
1007c478bd9Sstevel@tonic-gate   db = sqlite_open(DB_FILE, 0, 0);
1017c478bd9Sstevel@tonic-gate   if( db==0 ){
1027c478bd9Sstevel@tonic-gate     fprintf(stderr,"unable to initialize database\n");
1037c478bd9Sstevel@tonic-gate     exit(1);
1047c478bd9Sstevel@tonic-gate   }
1057c478bd9Sstevel@tonic-gate   rc = sqlite_exec(db, "CREATE TABLE t1(x);", 0,0,0);
1067c478bd9Sstevel@tonic-gate   if( rc ){
1077c478bd9Sstevel@tonic-gate     fprintf(stderr,"cannot create table t1: %d\n", rc);
1087c478bd9Sstevel@tonic-gate     exit(1);
1097c478bd9Sstevel@tonic-gate   }
1107c478bd9Sstevel@tonic-gate   sqlite_close(db);
1117c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(aThread)/sizeof(aThread[0]); i++){
1127c478bd9Sstevel@tonic-gate     pthread_create(&aThread[i], 0, worker, 0);
1137c478bd9Sstevel@tonic-gate   }
1147c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(aThread)/sizeof(aThread[i]); i++){
1157c478bd9Sstevel@tonic-gate     pthread_join(aThread[i], 0);
1167c478bd9Sstevel@tonic-gate   }
1177c478bd9Sstevel@tonic-gate   if( !all_stop ){
1187c478bd9Sstevel@tonic-gate     printf("Everything seems ok.\n");
1197c478bd9Sstevel@tonic-gate     return 0;
1207c478bd9Sstevel@tonic-gate   }else{
1217c478bd9Sstevel@tonic-gate     printf("We hit an error.\n");
1227c478bd9Sstevel@tonic-gate     return 1;
1237c478bd9Sstevel@tonic-gate   }
1247c478bd9Sstevel@tonic-gate }
125