/ Check-in [d8d3e6d0]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d8d3e6d04cbb9e3033ad8613e3dbd4ad0b01765a
User & Date: drh 2014-12-12 01:27:17
Context
2014-12-12
16:39
Add extra tests to threadtest3. check-in: f6bf86f9 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: d8d3e6d0 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: 03c443ea user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbeapi.c.

   396    396   static int doWalCallbacks(sqlite3 *db){
   397    397     int rc = SQLITE_OK;
   398    398   #ifndef SQLITE_OMIT_WAL
   399    399     int i;
   400    400     for(i=0; i<db->nDb; i++){
   401    401       Btree *pBt = db->aDb[i].pBt;
   402    402       if( pBt ){
   403         -      int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
          403  +      int nEntry;
          404  +      sqlite3BtreeEnter(pBt);
          405  +      nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
          406  +      sqlite3BtreeLeave(pBt);
   404    407         if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
   405    408           rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
   406    409         }
   407    410       }
   408    411     }
   409    412   #endif
   410    413     return rc;

Changes to test/threadtest4.c.

    12     12   ** This file implements a simple standalone program used to stress the
    13     13   ** SQLite library when accessing the same set of databases simultaneously
    14     14   ** from multiple threads in shared-cache mode.
    15     15   **
    16     16   ** This test program runs on unix-like systems only.  It uses pthreads.
    17     17   ** To compile:
    18     18   **
    19         -**     gcc -o tt4 -I. threadtest4.c sqlite3.c -ldl -lpthread
           19  +**     gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread
    20     20   **
    21     21   ** To run:
    22     22   **
    23         -**     ./tt4 10
           23  +**     ./a.out 10
           24  +**
           25  +** The argument is the number of threads.  There are also options, such
           26  +** as -wal and -multithread and -serialized.
    24     27   **
    25         -** The argument is the number of threads.
           28  +** Consider also compiling with clang instead of gcc and adding the
           29  +** -fsanitize=thread option.
    26     30   */
    27     31   #include "sqlite3.h"
    28     32   #include <pthread.h>
    29     33   #include <sched.h>
    30     34   #include <stdio.h>
    31     35   #include <stdlib.h>
    32     36   #include <string.h>
................................................................................
    36     40   /*
    37     41   ** An instance of the following structure is passed into each worker
    38     42   ** thread.
    39     43   */
    40     44   typedef struct WorkerInfo WorkerInfo;
    41     45   struct WorkerInfo {
    42     46     int tid;                    /* Thread ID */
           47  +  int nWorker;                /* Total number of workers */
    43     48     unsigned wkrFlags;          /* Flags */
    44     49     sqlite3 *mainDb;            /* Database connection of the main thread */
    45     50     sqlite3 *db;                /* Database connection of this thread */
    46     51     int nErr;                   /* Number of errors seen by this thread */
    47     52     int nTest;                  /* Number of tests run by this thread */
    48     53     char *zMsg;                 /* Message returned by this thread */
    49     54     pthread_t id;               /* Thread id */
................................................................................
   280    285     WorkerInfo *p = (WorkerInfo*)pArg;
   281    286     int iOuter;
   282    287     int i;
   283    288     int rc;
   284    289     sqlite3_stmt *pStmt;
   285    290   
   286    291     printf("worker %d startup\n", p->tid);  fflush(stdout);
   287         -  for(iOuter=1; iOuter<=4; iOuter++){
          292  +  for(iOuter=1; iOuter<=p->nWorker; iOuter++){
   288    293       worker_open_connection(p, iOuter);
   289    294       for(i=0; i<4; i++){
   290    295         worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter)%3 + 1);
   291    296         worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+1)%3 + 1);
   292    297         worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+2)%3 + 1);
   293    298       }
   294    299   
................................................................................
   298    303       if( rc!=SQLITE_ROW ){
   299    304         worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt));
   300    305       }else if( sqlite3_column_int(pStmt, 0)!=400 ){
   301    306         worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0));
   302    307       }
   303    308       if( p->nErr ) break;
   304    309       sqlite3_finalize(pStmt);
          310  +
          311  +    if( ((iOuter+p->tid)%3)==0 ){
          312  +      sqlite3_db_release_memory(p->db);
          313  +      p->nTest++;
          314  +    }
          315  +
          316  +    if( iOuter==p->tid ){
          317  +      pthread_mutex_lock(p->pWrMutex);
          318  +      run_sql(p, "VACUUM");
          319  +      pthread_mutex_unlock(p->pWrMutex);
          320  +    }
   305    321   
   306    322       worker_delete_all_content(p, (p->tid+iOuter)%2);
   307    323       worker_close_connection(p);
   308    324       p->db = 0;
   309    325     }
   310    326     worker_close_connection(p);
   311    327     printf("worker %d finished\n", p->tid); fflush(stdout);
................................................................................
   358    374     if( nWorker==0 ){ 
   359    375       fprintf(stderr,
   360    376          "usage:  %s ?OPTIONS? N\n"
   361    377          "N is the number of threads and must be at least 2.\n"
   362    378          "Options:\n"
   363    379          "  --serialized\n"
   364    380          "  --multithread\n"
          381  +       "  --wal\n"
          382  +       "  --trace\n"
   365    383          ,argv[0]
   366    384       );
   367    385       exit(1);
   368    386     }
   369    387     if( !sqlite3_threadsafe() ){
   370    388       fprintf(stderr, "requires a threadsafe build of SQLite\n");
   371    389       exit(1);
................................................................................
   402    420     run_sql(p, "CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)");
   403    421     run_sql(p, "CREATE INDEX test3.t3tid ON t3(tid)");
   404    422     run_sql(p, "CREATE INDEX test3.t3xy ON t3(x,y)");
   405    423     aInfo = safe_malloc( sizeof(*aInfo)*nWorker );
   406    424     memset(aInfo, 0, sizeof(*aInfo)*nWorker);
   407    425     for(i=0; i<nWorker; i++){
   408    426       aInfo[i].tid = i+1;
          427  +    aInfo[i].nWorker = nWorker;
   409    428       aInfo[i].wkrFlags = wkrFlags;
   410    429       aInfo[i].mainDb = db;
   411    430       aInfo[i].pWrMutex = &wrMutex;
   412    431       rc = pthread_create(&aInfo[i].id, 0, worker_thread, &aInfo[i]);
   413    432       if( rc!=0 ){
   414    433         fprintf(stderr, "thread creation failed for thread %d\n", i+1);
   415    434         exit(1);