diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/test/threadtest1.c')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/test/threadtest1.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/test/threadtest1.c b/libraries/sqlite/unix/sqlite-3.5.1/test/threadtest1.c new file mode 100644 index 0000000..56fcce3 --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/test/threadtest1.c | |||
@@ -0,0 +1,289 @@ | |||
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 | } | ||