Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add new tests to the threadtest4.c program. Fix a long-standing data race in WAL mode for shared-cache. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
d8d3e6d04cbb9e3033ad8613e3dbd4ad |
User & Date: | drh 2014-12-12 01:27:17.213 |
Context
2014-12-12
| ||
16:39 | Add extra tests to threadtest3. (check-in: f6bf86f907 user: dan tags: trunk) | |
01:27 | Add new tests to the threadtest4.c program. Fix a long-standing data race in WAL mode for shared-cache. (check-in: d8d3e6d04c user: drh tags: trunk) | |
00:52 | Remove the KeyInfo cache (for now - perhaps we will add it back in later - or maybe not since it provides negligible benefit but adds a lot of complexity and thread-safety risk). Add a mutex to ATTACH to deal with a data race. (check-in: 03c443eaf2 user: drh tags: trunk) | |
Changes
Changes to src/vdbeapi.c.
︙ | ︙ | |||
396 397 398 399 400 401 402 | static int doWalCallbacks(sqlite3 *db){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_WAL int i; for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ | > > | > | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | static int doWalCallbacks(sqlite3 *db){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_WAL int i; for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ int nEntry; sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry); } } } #endif return rc; |
︙ | ︙ |
Changes to test/threadtest4.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file implements a simple standalone program used to stress the ** SQLite library when accessing the same set of databases simultaneously ** from multiple threads in shared-cache mode. ** ** This test program runs on unix-like systems only. It uses pthreads. ** To compile: ** | | | | > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | ** This file implements a simple standalone program used to stress the ** SQLite library when accessing the same set of databases simultaneously ** from multiple threads in shared-cache mode. ** ** This test program runs on unix-like systems only. It uses pthreads. ** To compile: ** ** gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread ** ** To run: ** ** ./a.out 10 ** ** The argument is the number of threads. There are also options, such ** as -wal and -multithread and -serialized. ** ** Consider also compiling with clang instead of gcc and adding the ** -fsanitize=thread option. */ #include "sqlite3.h" #include <pthread.h> #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdarg.h> /* ** An instance of the following structure is passed into each worker ** thread. */ typedef struct WorkerInfo WorkerInfo; struct WorkerInfo { int tid; /* Thread ID */ int nWorker; /* Total number of workers */ unsigned wkrFlags; /* Flags */ sqlite3 *mainDb; /* Database connection of the main thread */ sqlite3 *db; /* Database connection of this thread */ int nErr; /* Number of errors seen by this thread */ int nTest; /* Number of tests run by this thread */ char *zMsg; /* Message returned by this thread */ pthread_t id; /* Thread id */ |
︙ | ︙ | |||
280 281 282 283 284 285 286 | WorkerInfo *p = (WorkerInfo*)pArg; int iOuter; int i; int rc; sqlite3_stmt *pStmt; printf("worker %d startup\n", p->tid); fflush(stdout); | | > > > > > > > > > > > | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | WorkerInfo *p = (WorkerInfo*)pArg; int iOuter; int i; int rc; sqlite3_stmt *pStmt; printf("worker %d startup\n", p->tid); fflush(stdout); for(iOuter=1; iOuter<=p->nWorker; iOuter++){ worker_open_connection(p, iOuter); for(i=0; i<4; i++){ worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter)%3 + 1); worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+1)%3 + 1); worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+2)%3 + 1); } pStmt = prep_sql(p->db, "SELECT count(a) FROM t1 WHERE tid=%d", p->tid); worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW ){ worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); }else if( sqlite3_column_int(pStmt, 0)!=400 ){ worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0)); } if( p->nErr ) break; sqlite3_finalize(pStmt); if( ((iOuter+p->tid)%3)==0 ){ sqlite3_db_release_memory(p->db); p->nTest++; } if( iOuter==p->tid ){ pthread_mutex_lock(p->pWrMutex); run_sql(p, "VACUUM"); pthread_mutex_unlock(p->pWrMutex); } worker_delete_all_content(p, (p->tid+iOuter)%2); worker_close_connection(p); p->db = 0; } worker_close_connection(p); printf("worker %d finished\n", p->tid); fflush(stdout); |
︙ | ︙ | |||
358 359 360 361 362 363 364 365 366 367 368 369 370 371 | if( nWorker==0 ){ fprintf(stderr, "usage: %s ?OPTIONS? N\n" "N is the number of threads and must be at least 2.\n" "Options:\n" " --serialized\n" " --multithread\n" ,argv[0] ); exit(1); } if( !sqlite3_threadsafe() ){ fprintf(stderr, "requires a threadsafe build of SQLite\n"); exit(1); | > > | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | if( nWorker==0 ){ fprintf(stderr, "usage: %s ?OPTIONS? N\n" "N is the number of threads and must be at least 2.\n" "Options:\n" " --serialized\n" " --multithread\n" " --wal\n" " --trace\n" ,argv[0] ); exit(1); } if( !sqlite3_threadsafe() ){ fprintf(stderr, "requires a threadsafe build of SQLite\n"); exit(1); |
︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 412 413 414 415 | run_sql(p, "CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)"); run_sql(p, "CREATE INDEX test3.t3tid ON t3(tid)"); run_sql(p, "CREATE INDEX test3.t3xy ON t3(x,y)"); aInfo = safe_malloc( sizeof(*aInfo)*nWorker ); memset(aInfo, 0, sizeof(*aInfo)*nWorker); for(i=0; i<nWorker; i++){ aInfo[i].tid = i+1; aInfo[i].wkrFlags = wkrFlags; aInfo[i].mainDb = db; aInfo[i].pWrMutex = &wrMutex; rc = pthread_create(&aInfo[i].id, 0, worker_thread, &aInfo[i]); if( rc!=0 ){ fprintf(stderr, "thread creation failed for thread %d\n", i+1); exit(1); | > | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | run_sql(p, "CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)"); run_sql(p, "CREATE INDEX test3.t3tid ON t3(tid)"); run_sql(p, "CREATE INDEX test3.t3xy ON t3(x,y)"); aInfo = safe_malloc( sizeof(*aInfo)*nWorker ); memset(aInfo, 0, sizeof(*aInfo)*nWorker); for(i=0; i<nWorker; i++){ aInfo[i].tid = i+1; aInfo[i].nWorker = nWorker; aInfo[i].wkrFlags = wkrFlags; aInfo[i].mainDb = db; aInfo[i].pWrMutex = &wrMutex; rc = pthread_create(&aInfo[i].id, 0, worker_thread, &aInfo[i]); if( rc!=0 ){ fprintf(stderr, "thread creation failed for thread %d\n", i+1); exit(1); |
︙ | ︙ |