Annotation of embedaddon/sqlite3/test/threadtest1.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** 2002 January 15
3: **
4: ** The author disclaims copyright to this source code. In place of
5: ** a legal notice, here is a blessing:
6: **
7: ** May you do good and not evil.
8: ** May you find forgiveness for yourself and forgive others.
9: ** May you share freely, never taking more than you give.
10: **
11: *************************************************************************
12: ** This file implements a simple standalone program used to test whether
13: ** or not the SQLite library is threadsafe.
14: **
15: ** Testing the thread safety of SQLite is difficult because there are very
16: ** few places in the code that are even potentially unsafe, and those
17: ** places execute for very short periods of time. So even if the library
18: ** is compiled with its mutexes disabled, it is likely to work correctly
19: ** in a multi-threaded program most of the time.
20: **
21: ** This file is NOT part of the standard SQLite library. It is used for
22: ** testing only.
23: */
24: #include "sqlite.h"
25: #include <pthread.h>
26: #include <sched.h>
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <unistd.h>
31:
32: /*
33: ** Enable for tracing
34: */
35: static int verbose = 0;
36:
37: /*
38: ** Come here to die.
39: */
40: static void Exit(int rc){
41: exit(rc);
42: }
43:
44: extern char *sqlite3_mprintf(const char *zFormat, ...);
45: extern char *sqlite3_vmprintf(const char *zFormat, va_list);
46:
47: /*
48: ** When a lock occurs, yield.
49: */
50: static int db_is_locked(void *NotUsed, int iCount){
51: /* sched_yield(); */
52: if( verbose ) printf("BUSY %s #%d\n", (char*)NotUsed, iCount);
53: usleep(100);
54: return iCount<25;
55: }
56:
57: /*
58: ** Used to accumulate query results by db_query()
59: */
60: struct QueryResult {
61: const char *zFile; /* Filename - used for error reporting */
62: int nElem; /* Number of used entries in azElem[] */
63: int nAlloc; /* Number of slots allocated for azElem[] */
64: char **azElem; /* The result of the query */
65: };
66:
67: /*
68: ** The callback function for db_query
69: */
70: static int db_query_callback(
71: void *pUser, /* Pointer to the QueryResult structure */
72: int nArg, /* Number of columns in this result row */
73: char **azArg, /* Text of data in all columns */
74: char **NotUsed /* Names of the columns */
75: ){
76: struct QueryResult *pResult = (struct QueryResult*)pUser;
77: int i;
78: if( pResult->nElem + nArg >= pResult->nAlloc ){
79: if( pResult->nAlloc==0 ){
80: pResult->nAlloc = nArg+1;
81: }else{
82: pResult->nAlloc = pResult->nAlloc*2 + nArg + 1;
83: }
84: pResult->azElem = realloc( pResult->azElem, pResult->nAlloc*sizeof(char*));
85: if( pResult->azElem==0 ){
86: fprintf(stdout,"%s: malloc failed\n", pResult->zFile);
87: return 1;
88: }
89: }
90: if( azArg==0 ) return 0;
91: for(i=0; i<nArg; i++){
92: pResult->azElem[pResult->nElem++] =
93: sqlite3_mprintf("%s",azArg[i] ? azArg[i] : "");
94: }
95: return 0;
96: }
97:
98: /*
99: ** Execute a query against the database. NULL values are returned
100: ** as an empty string. The list is terminated by a single NULL pointer.
101: */
102: char **db_query(sqlite *db, const char *zFile, const char *zFormat, ...){
103: char *zSql;
104: int rc;
105: char *zErrMsg = 0;
106: va_list ap;
107: struct QueryResult sResult;
108: va_start(ap, zFormat);
109: zSql = sqlite3_vmprintf(zFormat, ap);
110: va_end(ap);
111: memset(&sResult, 0, sizeof(sResult));
112: sResult.zFile = zFile;
113: if( verbose ) printf("QUERY %s: %s\n", zFile, zSql);
114: rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg);
115: if( rc==SQLITE_SCHEMA ){
116: if( zErrMsg ) free(zErrMsg);
117: rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg);
118: }
119: if( verbose ) printf("DONE %s %s\n", zFile, zSql);
120: if( zErrMsg ){
121: fprintf(stdout,"%s: query failed: %s - %s\n", zFile, zSql, zErrMsg);
122: free(zErrMsg);
123: free(zSql);
124: Exit(1);
125: }
126: sqlite3_free(zSql);
127: if( sResult.azElem==0 ){
128: db_query_callback(&sResult, 0, 0, 0);
129: }
130: sResult.azElem[sResult.nElem] = 0;
131: return sResult.azElem;
132: }
133:
134: /*
135: ** Execute an SQL statement.
136: */
137: void db_execute(sqlite *db, const char *zFile, const char *zFormat, ...){
138: char *zSql;
139: int rc;
140: char *zErrMsg = 0;
141: va_list ap;
142: va_start(ap, zFormat);
143: zSql = sqlite3_vmprintf(zFormat, ap);
144: va_end(ap);
145: if( verbose ) printf("EXEC %s: %s\n", zFile, zSql);
146: do{
147: rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
148: }while( rc==SQLITE_BUSY );
149: if( verbose ) printf("DONE %s: %s\n", zFile, zSql);
150: if( zErrMsg ){
151: fprintf(stdout,"%s: command failed: %s - %s\n", zFile, zSql, zErrMsg);
152: free(zErrMsg);
153: sqlite3_free(zSql);
154: Exit(1);
155: }
156: sqlite3_free(zSql);
157: }
158:
159: /*
160: ** Free the results of a db_query() call.
161: */
162: void db_query_free(char **az){
163: int i;
164: for(i=0; az[i]; i++){
165: sqlite3_free(az[i]);
166: }
167: free(az);
168: }
169:
170: /*
171: ** Check results
172: */
173: void db_check(const char *zFile, const char *zMsg, char **az, ...){
174: va_list ap;
175: int i;
176: char *z;
177: va_start(ap, az);
178: for(i=0; (z = va_arg(ap, char*))!=0; i++){
179: if( az[i]==0 || strcmp(az[i],z)!=0 ){
180: fprintf(stdout,"%s: %s: bad result in column %d: %s\n",
181: zFile, zMsg, i+1, az[i]);
182: db_query_free(az);
183: Exit(1);
184: }
185: }
186: va_end(ap);
187: db_query_free(az);
188: }
189:
190: pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
191: pthread_cond_t sig = PTHREAD_COND_INITIALIZER;
192: int thread_cnt = 0;
193:
194: static void *worker_bee(void *pArg){
195: const char *zFilename = (char*)pArg;
196: char *azErr;
197: int i, cnt;
198: int t = atoi(zFilename);
199: char **az;
200: sqlite *db;
201:
202: pthread_mutex_lock(&lock);
203: thread_cnt++;
204: pthread_mutex_unlock(&lock);
205: printf("%s: START\n", zFilename);
206: fflush(stdout);
207: for(cnt=0; cnt<10; cnt++){
208: sqlite3_open(&zFilename[2], &db);
209: if( db==0 ){
210: fprintf(stdout,"%s: can't open\n", zFilename);
211: Exit(1);
212: }
213: sqlite3_busy_handler(db, db_is_locked, zFilename);
214: db_execute(db, zFilename, "CREATE TABLE t%d(a,b,c);", t);
215: for(i=1; i<=100; i++){
216: db_execute(db, zFilename, "INSERT INTO t%d VALUES(%d,%d,%d);",
217: t, i, i*2, i*i);
218: }
219: az = db_query(db, zFilename, "SELECT count(*) FROM t%d", t);
220: db_check(zFilename, "tX size", az, "100", 0);
221: az = db_query(db, zFilename, "SELECT avg(b) FROM t%d", t);
222: db_check(zFilename, "tX avg", az, "101", 0);
223: db_execute(db, zFilename, "DELETE FROM t%d WHERE a>50", t);
224: az = db_query(db, zFilename, "SELECT avg(b) FROM t%d", t);
225: db_check(zFilename, "tX avg2", az, "51", 0);
226: for(i=1; i<=50; i++){
227: char z1[30], z2[30];
228: az = db_query(db, zFilename, "SELECT b, c FROM t%d WHERE a=%d", t, i);
229: sprintf(z1, "%d", i*2);
230: sprintf(z2, "%d", i*i);
231: db_check(zFilename, "readback", az, z1, z2, 0);
232: }
233: db_execute(db, zFilename, "DROP TABLE t%d;", t);
234: sqlite3_close(db);
235: }
236: printf("%s: END\n", zFilename);
237: /* unlink(zFilename); */
238: fflush(stdout);
239: pthread_mutex_lock(&lock);
240: thread_cnt--;
241: if( thread_cnt<=0 ){
242: pthread_cond_signal(&sig);
243: }
244: pthread_mutex_unlock(&lock);
245: return 0;
246: }
247:
248: int main(int argc, char **argv){
249: char *zFile;
250: int i, n;
251: pthread_t id;
252: if( argc>2 && strcmp(argv[1], "-v")==0 ){
253: verbose = 1;
254: argc--;
255: argv++;
256: }
257: if( argc<2 || (n=atoi(argv[1]))<1 ) n = 10;
258: for(i=0; i<n; i++){
259: char zBuf[200];
260: sprintf(zBuf, "testdb-%d", (i+1)/2);
261: unlink(zBuf);
262: }
263: for(i=0; i<n; i++){
264: zFile = sqlite3_mprintf("%d.testdb-%d", i%2+1, (i+2)/2);
265: if( (i%2)==0 ){
266: /* Remove both the database file and any old journal for the file
267: ** being used by this thread and the next one. */
268: char *zDb = &zFile[2];
269: char *zJournal = sqlite3_mprintf("%s-journal", zDb);
270: unlink(zDb);
271: unlink(zJournal);
272: free(zJournal);
273: }
274:
275: pthread_create(&id, 0, worker_bee, (void*)zFile);
276: pthread_detach(id);
277: }
278: pthread_mutex_lock(&lock);
279: while( thread_cnt>0 ){
280: pthread_cond_wait(&sig, &lock);
281: }
282: pthread_mutex_unlock(&lock);
283: for(i=0; i<n; i++){
284: char zBuf[200];
285: sprintf(zBuf, "testdb-%d", (i+1)/2);
286: unlink(zBuf);
287: }
288: return 0;
289: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>