/ Check-in [d7bb7ea4]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add extra tests to threadtest4.c. Fix a benign data race accessing the text encoding using ENC(db).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:d7bb7ea4ab97ad26f4c84c9b8dc2827010093803
User & Date: drh 2014-12-12 23:17:54
Context
2014-12-13
17:41
Further enhancements to threadtest3 stress tests. check-in: ba772cff user: dan tags: trunk
2014-12-12
23:17
Add extra tests to threadtest4.c. Fix a benign data race accessing the text encoding using ENC(db). check-in: d7bb7ea4 user: drh tags: trunk
16:39
Add extra tests to threadtest3. check-in: f6bf86f9 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

2754
2755
2756
2757
2758
2759
2760

2761
2762
2763
2764
2765
2766
2767
....
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
      rc = SQLITE_NOMEM;
    }
    sqlite3Error(db, rc);
    goto opendb_out;
  }
  sqlite3BtreeEnter(db->aDb[0].pBt);
  db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);

  sqlite3BtreeLeave(db->aDb[0].pBt);
  db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);

  /* The default safety_level for the main database is 'full'; for the temp
  ** database it is 'NONE'. This matches the pager layer defaults.  
  */
  db->aDb[0].zName = "main";
................................................................................
  sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
  if( zFilename8 ){
    rc = openDatabase(zFilename8, ppDb,
                      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
    assert( *ppDb || rc==SQLITE_NOMEM );
    if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
      ENC(*ppDb) = SQLITE_UTF16NATIVE;
    }
  }else{
    rc = SQLITE_NOMEM;
  }
  sqlite3ValueFree(pVal);

  return sqlite3ApiExit(0, rc);







>







 







|







2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
....
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
      rc = SQLITE_NOMEM;
    }
    sqlite3Error(db, rc);
    goto opendb_out;
  }
  sqlite3BtreeEnter(db->aDb[0].pBt);
  db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
  if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
  sqlite3BtreeLeave(db->aDb[0].pBt);
  db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);

  /* The default safety_level for the main database is 'full'; for the temp
  ** database it is 'NONE'. This matches the pager layer defaults.  
  */
  db->aDb[0].zName = "main";
................................................................................
  sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8);
  if( zFilename8 ){
    rc = openDatabase(zFilename8, ppDb,
                      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
    assert( *ppDb || rc==SQLITE_NOMEM );
    if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){
      SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
    }
  }else{
    rc = SQLITE_NOMEM;
  }
  sqlite3ValueFree(pVal);

  return sqlite3ApiExit(0, rc);

Changes to src/pragma.c.

2076
2077
2078
2079
2080
2081
2082

2083
2084
2085
2086
2087
2088
2089
2090
      */
      if( 
        !(DbHasProperty(db, 0, DB_SchemaLoaded)) || 
        DbHasProperty(db, 0, DB_Empty) 
      ){
        for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
          if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){

            ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
            break;
          }
        }
        if( !pEnc->zName ){
          sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
        }
      }







>
|







2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
      */
      if( 
        !(DbHasProperty(db, 0, DB_SchemaLoaded)) || 
        DbHasProperty(db, 0, DB_Empty) 
      ){
        for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
          if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
            SCHEMA_ENC(db) = ENC(db) =
                pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
            break;
          }
        }
        if( !pEnc->zName ){
          sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
        }
      }

Changes to src/prepare.c.

390
391
392
393
394
395
396

397
398
399

400
401
402
403
404
405
406
** file was of zero-length, then the DB_Empty flag is also set.
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
  int i, rc;
  int commit_internal = !(db->flags&SQLITE_InternChanges);
  
  assert( sqlite3_mutex_held(db->mutex) );

  assert( db->init.busy==0 );
  rc = SQLITE_OK;
  db->init.busy = 1;

  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
    rc = sqlite3InitOne(db, i, pzErrMsg);
    if( rc ){
      sqlite3ResetOneSchema(db, i);
    }
  }







>



>







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
** file was of zero-length, then the DB_Empty flag is also set.
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
  int i, rc;
  int commit_internal = !(db->flags&SQLITE_InternChanges);
  
  assert( sqlite3_mutex_held(db->mutex) );
  assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
  assert( db->init.busy==0 );
  rc = SQLITE_OK;
  db->init.busy = 1;
  ENC(db) = SCHEMA_ENC(db);
  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
    rc = sqlite3InitOne(db, i, pzErrMsg);
    if( rc ){
      sqlite3ResetOneSchema(db, i);
    }
  }

Changes to src/sqliteInt.h.

1055
1056
1057
1058
1059
1060
1061

1062
1063
1064
1065
1066
1067
1068
....
1156
1157
1158
1159
1160
1161
1162
1163

1164
1165
1166
1167
1168
1169
1170
  int flags;                    /* Miscellaneous flags. See below */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  i64 szMmap;                   /* Default mmap_size setting */
  unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
  int errCode;                  /* Most recent error code (SQLITE_*) */
  int errMask;                  /* & result codes with this before returning */
  u16 dbOptFlags;               /* Flags to enable/disable optimizations */

  u8 autoCommit;                /* The auto-commit flag. */
  u8 temp_store;                /* 1: file 2: memory 0: default */
  u8 mallocFailed;              /* True if we have seen a malloc failure */
  u8 dfltLockMode;              /* Default locking-mode for attached dbs */
  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  u8 suppressErr;               /* Do not issue error messages if true */
  u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
................................................................................
  sqlite3_userauth auth;        /* User authentication information */
#endif
};

/*
** A macro to discover the encoding of a database.
*/
#define ENC(db) ((db)->aDb[0].pSchema->enc)


/*
** Possible values for the sqlite3.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_InternChanges  0x00000002  /* Uncommitted Hash table changes */
#define SQLITE_FullFSync      0x00000004  /* Use full fsync on the backend */







>







 







|
>







1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
....
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  int flags;                    /* Miscellaneous flags. See below */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  i64 szMmap;                   /* Default mmap_size setting */
  unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
  int errCode;                  /* Most recent error code (SQLITE_*) */
  int errMask;                  /* & result codes with this before returning */
  u16 dbOptFlags;               /* Flags to enable/disable optimizations */
  u8 enc;                       /* Text encoding */
  u8 autoCommit;                /* The auto-commit flag. */
  u8 temp_store;                /* 1: file 2: memory 0: default */
  u8 mallocFailed;              /* True if we have seen a malloc failure */
  u8 dfltLockMode;              /* Default locking-mode for attached dbs */
  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  u8 suppressErr;               /* Do not issue error messages if true */
  u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
................................................................................
  sqlite3_userauth auth;        /* User authentication information */
#endif
};

/*
** A macro to discover the encoding of a database.
*/
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
#define ENC(db)        ((db)->enc)

/*
** Possible values for the sqlite3.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_InternChanges  0x00000002  /* Uncommitted Hash table changes */
#define SQLITE_FullFSync      0x00000004  /* Use full fsync on the backend */

Changes to test/threadtest4.c.

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
    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);







<

>





>
>
>
>
>
>
>
>
>
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
    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));
    }

    sqlite3_finalize(pStmt);
    if( p->nErr ) break;

    if( ((iOuter+p->tid)%3)==0 ){
      sqlite3_db_release_memory(p->db);
      p->nTest++;
    }

    pthread_mutex_lock(p->pWrMutex);
    run_sql(p, "BEGIN;");
    run_sql(p, "UPDATE t1 SET c=NULL WHERE a=55");
    run_sql(p, "UPDATE t2 SET f=NULL WHERE d=42");
    run_sql(p, "UPDATE t3 SET z=NULL WHERE x=31");
    run_sql(p, "ROLLBACK;");
    p->nTest++;
    pthread_mutex_unlock(p->pWrMutex);


    if( iOuter==p->tid ){
      pthread_mutex_lock(p->pWrMutex);
      run_sql(p, "VACUUM");
      pthread_mutex_unlock(p->pWrMutex);
    }

    pStmt = prep_sql(p->db,
       "SELECT t1.rowid, t2.rowid, t3.rowid"
       "  FROM t1, t2, t3"
       " WHERE t1.tid=%d AND t2.tid=%d AND t3.tid=%d"
       "   AND t1.a<>t2.d AND t2.d<>t3.x"
       " ORDER BY 1, 2, 3"
       ,p->tid, p->tid, p->tid);
    worker_trace(p, "query [%s]", sqlite3_sql(pStmt));
    for(i=0; i<p->nWorker; i++){
      rc = sqlite3_step(pStmt);
      if( rc!=SQLITE_ROW ){
        worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt));
        break;
      }
      sched_yield();
    }
    sqlite3_finalize(pStmt);
    if( p->nErr ) break;

    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);