Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ee46c01b4 | |||
| 9af10620ec | |||
| d44b786ff6 | |||
| 053542d72a | |||
| 9bd3cc4681 | |||
| 0420954606 | |||
| ef15c6e9e6 | |||
| 2ea0bafae2 |
@@ -625,9 +625,15 @@ test: testfixture$(EXE) sqlite3$(EXE)
|
||||
# threadtest runs a few thread-safety tests that are implemented in C. This
|
||||
# target is invoked by the releasetest.tcl script.
|
||||
#
|
||||
threadtest3$(EXE): sqlite3.o $(TOP)/test/threadtest3.c $(TOP)/test/tt3_checkpoint.c
|
||||
$(TCCX) -O2 sqlite3.o $(TOP)/test/threadtest3.c \
|
||||
-o threadtest3$(EXE) $(THREADLIB)
|
||||
THREADTEST3_SRC = $(TOP)/test/threadtest3.c \
|
||||
$(TOP)/test/tt3_checkpoint.c \
|
||||
$(TOP)/test/tt3_index.c \
|
||||
$(TOP)/test/tt3_vacuum.c \
|
||||
$(TOP)/test/tt3_stress.c \
|
||||
$(TOP)/test/tt3_lookaside1.c
|
||||
|
||||
threadtest3$(EXE): sqlite3.o $(THREADTEST3_SRC)
|
||||
$(TCCX) $(TOP)/test/threadtest3.c sqlite3.o -o $@ $(THREADLIB)
|
||||
|
||||
threadtest: threadtest3$(EXE)
|
||||
./threadtest3$(EXE)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Make\ssure\sthe\sBtree\smutex\sis\sheld\swhen\ssetting\sthe\slocking\smode\sand\sthe\nsecure\sdelete\sflag\swhen\sattaching\sa\sshared-cache\sdatabase.
|
||||
D 2014-12-12T00:40:58.882
|
||||
C Changes\sto\sthreadtest3\sso\sthat\s"stress2"\sis\smore\ssimilar\sto\sthe\sSDS\sstress\stest.
|
||||
D 2014-12-15T20:49:26.942
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -152,7 +152,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 084976077a4aa3bd985154b5423e7aed88e4a2e9
|
||||
F main.mk 9f8c54fe62b60e0a24a2e65cfc8d2add063dda07
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@@ -195,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
|
||||
F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660
|
||||
F src/main.c 1f40f66165a6609203a5ff7ecb0292b90b302130
|
||||
F src/main.c 48e0410a661c629471ca9061d4153245cc9f853b
|
||||
F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f
|
||||
@@ -222,8 +222,8 @@ F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45
|
||||
F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4
|
||||
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
|
||||
F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98
|
||||
F src/pragma.c d54cdd40b63d608f2d95b7482c710690e3593a73
|
||||
F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7
|
||||
F src/pragma.c c93be505649183b2d80082c2eef1a56879dabfe6
|
||||
F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9
|
||||
F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada
|
||||
@@ -233,12 +233,12 @@ F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf
|
||||
F src/sqlite.h.in 116dc731361549ee3fc79dcebace11b57d24dcfd
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h 073d54f7a631b978b66d50d255c84549fb9e5429
|
||||
F src/sqliteInt.h d36da9a07130cae13cbfee0986bf20028cb01465
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 81712116e826b0089bb221b018929536b2b5406f
|
||||
F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc
|
||||
F src/tclsqlite.c c6a21c64da1490e14d53cdc2062d1e2e57942622
|
||||
F src/test1.c 7e806af12d7915445e46407d32b275d8ca9db4e7
|
||||
F src/test1.c 56e33bf6b1827c6ca7520c189131ddd778fb2267
|
||||
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@@ -294,7 +294,7 @@ F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c
|
||||
F src/vdbe.c 1a9e671c9cfc259e4d2affc71f7df4a4c00a842c
|
||||
F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
|
||||
F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78
|
||||
F src/vdbeapi.c f8dd2d33a30938188fc292d524e88a91f2e65887
|
||||
F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71
|
||||
F src/vdbeaux.c 6f7f39c3fcf0f5923758df8561bb5d843908a553
|
||||
F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778
|
||||
F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
|
||||
@@ -478,6 +478,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52
|
||||
F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585
|
||||
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
|
||||
F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a
|
||||
F test/e_walauto.test a1fa9d36c160cc4001a934d1e009aae597b440b7
|
||||
F test/e_walckpt.test 3116a98fa0dd9b2c9e493de7c59730adfe436746
|
||||
F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
@@ -912,8 +913,8 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46
|
||||
F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
|
||||
F test/threadtest3.c 2b6e07e915c383c250a5b531cf6ef163a3047d7e
|
||||
F test/threadtest4.c 38cb574939d5e0c8bd3baa5eb45def2ac6da4db4
|
||||
F test/threadtest3.c f8c6595664a4c5ef5f28d97a612386fe14dd1940
|
||||
F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925
|
||||
F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c
|
||||
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
|
||||
F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2
|
||||
@@ -1076,9 +1077,11 @@ F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test a68980c5955d62ee24be6f97129d824f199f9a4c
|
||||
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/triggerE.test 355e9c5cbaed5cd039a60baad1fb2197caeb8e52
|
||||
F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af
|
||||
F test/tt3_index.c 14f4b0cc3f4c05353e25778cf531c9d6e3b0d27f
|
||||
F test/tt3_lookaside1.c 0b5b79ba37f21a1eb849cd4a54eed367f4d4aaaf
|
||||
F test/tt3_checkpoint.c 5e63ee65ed5f87176e25a996480cb02c6caec8b4
|
||||
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
|
||||
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
|
||||
F test/tt3_stress.c c57d804716165811d979d4a719e05baccd79277f
|
||||
F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
@@ -1229,7 +1232,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P cefad47ec2ad58d7ecd58bab9a261e4d5816cd69
|
||||
R 43ea10bc03cfab6b8cae2a465b94aee2
|
||||
U drh
|
||||
Z 01d198dabe70d93c23f2c971bf866fd9
|
||||
P 62ef45140cdbff5eeb8bef506db8b78ced3ace94
|
||||
R 9a6502f6d41e6a843f5a509613ed553f
|
||||
T *branch * threadtest3
|
||||
T *sym-threadtest3 *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 02118ab9cf865ac1e1c9e40290c79fe8
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
6bef7ede2bbf0a51729e1943b0b0c895cb57c718
|
||||
5648af96d8e2521c5b0cca19f1358374d032394d
|
||||
+2
-1
@@ -2758,6 +2758,7 @@ static int openDatabase(
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -2916,7 +2917,7 @@ int sqlite3_open16(
|
||||
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;
|
||||
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
|
||||
+2
-1
@@ -2080,7 +2080,8 @@ void sqlite3Pragma(
|
||||
){
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
|
||||
ENC(pParse->db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
|
||||
SCHEMA_ENC(db) = ENC(db) =
|
||||
pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,9 +394,11 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
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);
|
||||
|
||||
+3
-1
@@ -1059,6 +1059,7 @@ struct sqlite3 {
|
||||
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 */
|
||||
@@ -1160,7 +1161,8 @@ struct sqlite3 {
|
||||
/*
|
||||
** A macro to discover the encoding of a database.
|
||||
*/
|
||||
#define ENC(db) ((db)->aDb[0].pSchema->enc)
|
||||
#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc)
|
||||
#define ENC(db) ((db)->enc)
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite3.flags.
|
||||
|
||||
+38
@@ -5726,6 +5726,43 @@ static int test_wal_checkpoint_v2(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_wal_autocheckpoint db VALUE
|
||||
*/
|
||||
static int test_wal_autocheckpoint(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
int iVal;
|
||||
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB VALUE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
|
||||
|| Tcl_GetIntFromObj(0, objv[2], &iVal)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_wal_autocheckpoint(db, iVal);
|
||||
Tcl_ResetResult(interp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
const char *zErrCode = sqlite3ErrName(rc);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(zErrCode, -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** tclcmd: test_sqlite3_log ?SCRIPT?
|
||||
*/
|
||||
@@ -6787,6 +6824,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#endif
|
||||
{ "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 },
|
||||
{ "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 },
|
||||
{ "sqlite3_wal_autocheckpoint",test_wal_autocheckpoint, 0 },
|
||||
{ "test_sqlite3_log", test_sqlite3_log, 0 },
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
{ "print_explain_query_plan", test_print_eqp, 0 },
|
||||
|
||||
+4
-1
@@ -400,7 +400,10 @@ static int doWalCallbacks(sqlite3 *db){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
# 2014 December 04
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
set testprefix e_walauto
|
||||
|
||||
|
||||
proc read_nbackfill {} {
|
||||
seek $::shmfd 96
|
||||
binary scan [read $::shmfd 4] i nBackfill
|
||||
set nBackfill
|
||||
}
|
||||
proc read_mxframe {} {
|
||||
seek $::shmfd 16
|
||||
binary scan [read $::shmfd 4] i mxFrame
|
||||
set mxFrame
|
||||
}
|
||||
|
||||
# Assuming that the main db for database handle
|
||||
#
|
||||
proc do_autocommit_threshold_test {tn value} {
|
||||
|
||||
set nBackfillSaved [read_nbackfill]
|
||||
while {1} {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
if {[read_mxframe] >= $value} break
|
||||
}
|
||||
|
||||
set nBackfillNew [read_nbackfill]
|
||||
uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1]
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used
|
||||
# to invoke this interface from SQL.
|
||||
#
|
||||
# All tests in this file are run twice - once using the
|
||||
# sqlite3_wal_autocheckpoint() API, and once using "PRAGMA
|
||||
# wal_autocheckpoint".
|
||||
#
|
||||
foreach {tn code} {
|
||||
1 {
|
||||
proc autocheckpoint {db value} {
|
||||
uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"]
|
||||
}
|
||||
}
|
||||
|
||||
2 {
|
||||
proc autocheckpoint {db value} {
|
||||
uplevel [list sqlite3_wal_autocheckpoint $db $value]
|
||||
return $value
|
||||
}
|
||||
}
|
||||
} {
|
||||
|
||||
eval $code
|
||||
|
||||
reset_db
|
||||
do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal}
|
||||
do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) }
|
||||
set shmfd [open "test.db-shm"]
|
||||
|
||||
# EVIDENCE-OF: R-41531-51083 Every new database connection defaults to
|
||||
# having the auto-checkpoint enabled with a threshold of 1000 or
|
||||
# SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages.
|
||||
#
|
||||
do_autocommit_threshold_test 1.$tn.2 1000
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
do_autocommit_threshold_test 1.$tn.3 1000
|
||||
|
||||
# EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a
|
||||
# wrapper around sqlite3_wal_hook() that causes any database on database
|
||||
# connection D to automatically checkpoint after committing a
|
||||
# transaction if there are N or more frames in the write-ahead log file.
|
||||
#
|
||||
do_test 1.$tn.4 {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
autocheckpoint db 100
|
||||
} {100}
|
||||
do_autocommit_threshold_test 1.$tn.5 100
|
||||
|
||||
do_test 1.$tn.6 {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
autocheckpoint db 500
|
||||
} {500}
|
||||
do_autocommit_threshold_test 1.$tn.7 500
|
||||
|
||||
# EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the
|
||||
# nFrame parameter disables automatic checkpoints entirely.
|
||||
#
|
||||
do_test 1.$tn.7 {
|
||||
autocheckpoint db 0 ;# Set to zero
|
||||
for {set i 0} {$i < 10000} {incr i} {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
}
|
||||
expr {[file size test.db-wal] > (5 * 1024 * 1024)}
|
||||
} 1
|
||||
do_test 1.$tn.8 {
|
||||
sqlite3_wal_checkpoint_v2 db truncate
|
||||
file size test.db-wal
|
||||
} 0
|
||||
do_test 1.$tn.9 {
|
||||
autocheckpoint db -4 ;# Set to a negative value
|
||||
for {set i 0} {$i < 10000} {incr i} {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
}
|
||||
expr {[file size test.db-wal] > (5 * 1024 * 1024)}
|
||||
} 1
|
||||
|
||||
# EVIDENCE-OF: R-10203-42688 The callback registered by this function
|
||||
# replaces any existing callback registered using sqlite3_wal_hook().
|
||||
#
|
||||
set ::wal_hook_callback 0
|
||||
proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 }
|
||||
do_test 1.$tn.10.1 {
|
||||
db wal_hook wal_hook_callback
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
set ::wal_hook_callback
|
||||
} 2
|
||||
do_test 1.$tn.10.2 {
|
||||
autocheckpoint db 100
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
set ::wal_hook_callback
|
||||
} 2
|
||||
|
||||
# EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using
|
||||
# sqlite3_wal_hook() disables the automatic checkpoint mechanism
|
||||
# configured by this function.
|
||||
do_test 1.$tn.11.1 {
|
||||
sqlite3_wal_checkpoint_v2 db truncate
|
||||
file size test.db-wal
|
||||
} 0
|
||||
do_test 1.$tn.11.2 {
|
||||
autocheckpoint db 100
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
}
|
||||
expr {[file size test.db-wal] < (1 * 1024 * 1024)}
|
||||
} 1
|
||||
do_test 1.$tn.11.3 {
|
||||
db wal_hook wal_hook_callback
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
}
|
||||
expr {[file size test.db-wal] < (1 * 1024 * 1024)}
|
||||
} 0
|
||||
|
||||
# EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism
|
||||
# are PASSIVE.
|
||||
#
|
||||
set ::busy_callback_count 0
|
||||
proc busy_callback {args} {
|
||||
puts Hello
|
||||
incr ::busy_callback_count
|
||||
return 0
|
||||
}
|
||||
do_test 1.$tn.12.1 {
|
||||
sqlite3_wal_checkpoint_v2 db truncate
|
||||
autocheckpoint db 100
|
||||
db busy busy_callback
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
} {}
|
||||
do_test 1.$tn.12.2 {
|
||||
sqlite3 db2 test.db
|
||||
db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; }
|
||||
read_nbackfill
|
||||
} {0}
|
||||
do_test 1.$tn.12.3 {
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
}
|
||||
read_nbackfill
|
||||
} {2}
|
||||
do_test 1.$tn.12.4 {
|
||||
set ::busy_callback_count
|
||||
} {0}
|
||||
db2 close
|
||||
|
||||
do_test 1.$tn.12.5 {
|
||||
db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
|
||||
read_nbackfill
|
||||
} {1559}
|
||||
|
||||
db close
|
||||
close $shmfd
|
||||
}
|
||||
|
||||
finish_test
|
||||
+89
-68
@@ -47,10 +47,13 @@
|
||||
#define execsql_i64(x,y,...) (SEL(x), execsql_i64_x(x,y,__VA_ARGS__))
|
||||
#define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__))
|
||||
#define execsql(x,y,...) (SEL(x), (void)execsql_i64_x(x,y,__VA_ARGS__))
|
||||
#define sql_script_printf(x,y,z,...) ( \
|
||||
SEL(x), sql_script_printf_x(x,y,z,__VA_ARGS__) \
|
||||
)
|
||||
|
||||
/* Thread functions */
|
||||
#define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z))
|
||||
#define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z))
|
||||
#define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z))
|
||||
#define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z))
|
||||
|
||||
/* Timer functions */
|
||||
#define setstoptime(y,z) (SEL(y), setstoptime_x(y,z))
|
||||
@@ -64,6 +67,9 @@
|
||||
#define filesize(y,z) (SEL(y), filesize_x(y,z))
|
||||
#define filecopy(x,y,z) (SEL(x), filecopy_x(x,y,z))
|
||||
|
||||
#define PTR2INT(x) ((int)((intptr_t)x))
|
||||
#define INT2PTR(x) ((void*)((intptr_t)x))
|
||||
|
||||
/*
|
||||
** End of test code/infrastructure interface macros.
|
||||
*************************************************************************/
|
||||
@@ -115,7 +121,10 @@ struct MD5Context {
|
||||
int isInit;
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
union {
|
||||
unsigned char in[64];
|
||||
uint32 in32[16];
|
||||
} u;
|
||||
};
|
||||
typedef struct MD5Context MD5Context;
|
||||
|
||||
@@ -264,7 +273,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = (unsigned char *)ctx->in + t;
|
||||
unsigned char *p = (unsigned char *)ctx->u.in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
@@ -272,8 +281,8 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
byteReverse(ctx->u.in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->u.in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
@@ -281,16 +290,16 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
memcpy(ctx->u.in, buf, 64);
|
||||
byteReverse(ctx->u.in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->u.in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
memcpy(ctx->u.in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -306,7 +315,7 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
p = ctx->u.in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
@@ -316,25 +325,25 @@ static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
byteReverse(ctx->u.in, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->u.in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
memset(ctx->u.in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
byteReverse(ctx->in, 14);
|
||||
byteReverse(ctx->u.in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
|
||||
((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
|
||||
ctx->u.in32[14] = ctx->bits[0];
|
||||
ctx->u.in32[15] = ctx->bits[1];
|
||||
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->in);
|
||||
MD5Transform(ctx->buf, (uint32 *)ctx->u.in);
|
||||
byteReverse((unsigned char *)ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, 16);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it is sensitive */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -398,9 +407,6 @@ typedef struct Thread Thread;
|
||||
/* Total number of errors in this process so far. */
|
||||
static int nGlobalErr = 0;
|
||||
|
||||
/* Set to true to run in "process" instead of "thread" mode. */
|
||||
static int bProcessMode = 0;
|
||||
|
||||
struct Error {
|
||||
int rc;
|
||||
int iLine;
|
||||
@@ -421,10 +427,10 @@ struct Statement {
|
||||
|
||||
struct Thread {
|
||||
int iTid; /* Thread number within test */
|
||||
int iArg; /* Integer argument passed by caller */
|
||||
void* pArg; /* Pointer argument passed by caller */
|
||||
|
||||
pthread_t tid; /* Thread id */
|
||||
char *(*xProc)(int, int); /* Thread main proc */
|
||||
char *(*xProc)(int, void*); /* Thread main proc */
|
||||
Thread *pNext; /* Next in this list of threads */
|
||||
};
|
||||
|
||||
@@ -506,8 +512,9 @@ static void opendb_x(
|
||||
){
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
int rc;
|
||||
int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;
|
||||
if( bDelete ) unlink(zFile);
|
||||
rc = sqlite3_open(zFile, &pDb->db);
|
||||
rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0);
|
||||
if( rc ){
|
||||
sqlite_error(pErr, pDb, "open");
|
||||
sqlite3_close(pDb->db);
|
||||
@@ -556,6 +563,22 @@ static void sql_script_x(
|
||||
}
|
||||
}
|
||||
|
||||
static void sql_script_printf_x(
|
||||
Error *pErr, /* IN/OUT: Error code */
|
||||
Sqlite *pDb, /* Database handle */
|
||||
const char *zFormat, /* SQL printf format string */
|
||||
... /* Printf args */
|
||||
){
|
||||
va_list ap; /* ... printf arguments */
|
||||
va_start(ap, zFormat);
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
char *zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
pErr->rc = sqlite3_exec(pDb->db, zSql, 0, 0, &pErr->zErr);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static Statement *getSqlStatement(
|
||||
Error *pErr, /* IN/OUT: Error code */
|
||||
Sqlite *pDb, /* Database handle */
|
||||
@@ -624,11 +647,9 @@ static i64 execsql_i64_x(
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pStmt; /* SQL statement to execute */
|
||||
va_list ap; /* ... arguments */
|
||||
int i; /* Used to iterate through parameters */
|
||||
va_start(ap, pDb);
|
||||
pStmt = getAndBindSqlStatement(pErr, pDb, ap);
|
||||
if( pStmt ){
|
||||
int rc;
|
||||
int first = 1;
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
if( first && sqlite3_column_count(pStmt)>0 ){
|
||||
@@ -663,11 +684,9 @@ static char * execsql_text_x(
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pStmt; /* SQL statement to execute */
|
||||
va_list ap; /* ... arguments */
|
||||
int i; /* Used to iterate through parameters */
|
||||
va_start(ap, iSlot);
|
||||
pStmt = getAndBindSqlStatement(pErr, pDb, ap);
|
||||
if( pStmt ){
|
||||
int rc;
|
||||
int first = 1;
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
if( first && sqlite3_column_count(pStmt)>0 ){
|
||||
@@ -693,14 +712,13 @@ static void integrity_check_x(
|
||||
){
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
Statement *pStatement; /* Statement to execute */
|
||||
int rc; /* Return code */
|
||||
char *zErr = 0; /* Integrity check error */
|
||||
|
||||
pStatement = getSqlStatement(pErr, pDb, "PRAGMA integrity_check");
|
||||
if( pStatement ){
|
||||
sqlite3_stmt *pStmt = pStatement->pStmt;
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
const char *z = sqlite3_column_text(pStmt, 0);
|
||||
const char *z = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
if( strcmp(z, "ok") ){
|
||||
if( zErr==0 ){
|
||||
zErr = sqlite3_mprintf("%s", z);
|
||||
@@ -721,14 +739,14 @@ static void integrity_check_x(
|
||||
|
||||
static void *launch_thread_main(void *pArg){
|
||||
Thread *p = (Thread *)pArg;
|
||||
return (void *)p->xProc(p->iTid, p->iArg);
|
||||
return (void *)p->xProc(p->iTid, p->pArg);
|
||||
}
|
||||
|
||||
static void launch_thread_x(
|
||||
Error *pErr, /* IN/OUT: Error code */
|
||||
Threadset *pThreads, /* Thread set */
|
||||
char *(*xProc)(int, int), /* Proc to run */
|
||||
int iArg /* Argument passed to thread proc */
|
||||
char *(*xProc)(int, void*), /* Proc to run */
|
||||
void *pArg /* Argument passed to thread proc */
|
||||
){
|
||||
if( pErr->rc==SQLITE_OK ){
|
||||
int iTid = ++pThreads->iMaxTid;
|
||||
@@ -738,7 +756,7 @@ static void launch_thread_x(
|
||||
p = (Thread *)sqlite3_malloc(sizeof(Thread));
|
||||
memset(p, 0, sizeof(Thread));
|
||||
p->iTid = iTid;
|
||||
p->iArg = iArg;
|
||||
p->pArg = pArg;
|
||||
p->xProc = xProc;
|
||||
|
||||
rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p);
|
||||
@@ -895,7 +913,7 @@ static int timetostop_x(
|
||||
#define WALTHREAD1_NTHREAD 10
|
||||
#define WALTHREAD3_NTHREAD 6
|
||||
|
||||
static char *walthread1_thread(int iTid, int iArg){
|
||||
static char *walthread1_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nIter = 0; /* Iterations so far */
|
||||
@@ -934,7 +952,7 @@ static char *walthread1_thread(int iTid, int iArg){
|
||||
return sqlite3_mprintf("%d iterations", nIter);
|
||||
}
|
||||
|
||||
static char *walthread1_ckpt_thread(int iTid, int iArg){
|
||||
static char *walthread1_ckpt_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nCkpt = 0; /* Checkpoints so far */
|
||||
@@ -977,10 +995,11 @@ static void walthread1(int nMs){
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
static char *walthread2_thread(int iTid, int iArg){
|
||||
static char *walthread2_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int anTrans[2] = {0, 0}; /* Number of WAL and Rollback transactions */
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
const char *zJournal = "PRAGMA journal_mode = WAL";
|
||||
if( iArg ){ zJournal = "PRAGMA journal_mode = DELETE"; }
|
||||
@@ -1026,17 +1045,18 @@ static void walthread2(int nMs){
|
||||
setstoptime(&err, nMs);
|
||||
launch_thread(&err, &threads, walthread2_thread, 0);
|
||||
launch_thread(&err, &threads, walthread2_thread, 0);
|
||||
launch_thread(&err, &threads, walthread2_thread, 1);
|
||||
launch_thread(&err, &threads, walthread2_thread, 1);
|
||||
launch_thread(&err, &threads, walthread2_thread, (void*)1);
|
||||
launch_thread(&err, &threads, walthread2_thread, (void*)1);
|
||||
join_all_threads(&err, &threads);
|
||||
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
static char *walthread3_thread(int iTid, int iArg){
|
||||
static char *walthread3_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 iNextWrite; /* Next value this thread will write */
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
sql_script(&err, &db, "PRAGMA wal_autocheckpoint = 10");
|
||||
@@ -1087,14 +1107,14 @@ static void walthread3(int nMs){
|
||||
|
||||
setstoptime(&err, nMs);
|
||||
for(i=0; i<WALTHREAD3_NTHREAD; i++){
|
||||
launch_thread(&err, &threads, walthread3_thread, i);
|
||||
launch_thread(&err, &threads, walthread3_thread, INT2PTR(i));
|
||||
}
|
||||
join_all_threads(&err, &threads);
|
||||
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
static char *walthread4_reader_thread(int iTid, int iArg){
|
||||
static char *walthread4_reader_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
@@ -1108,7 +1128,7 @@ static char *walthread4_reader_thread(int iTid, int iArg){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *walthread4_writer_thread(int iTid, int iArg){
|
||||
static char *walthread4_writer_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 iRow = 1;
|
||||
@@ -1148,7 +1168,7 @@ static void walthread4(int nMs){
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
static char *walthread5_thread(int iTid, int iArg){
|
||||
static char *walthread5_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 nRow;
|
||||
@@ -1280,7 +1300,7 @@ static void cgt_pager_1(int nMs){
|
||||
** is an attempt to find a bug reported to us.
|
||||
*/
|
||||
|
||||
static char *dynamic_triggers_1(int iTid, int iArg){
|
||||
static char *dynamic_triggers_1(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int nDrop = 0;
|
||||
@@ -1326,12 +1346,13 @@ static char *dynamic_triggers_1(int iTid, int iArg){
|
||||
nDrop++;
|
||||
}
|
||||
}
|
||||
closedb(&err, &db);
|
||||
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("%d created, %d dropped", nCreate, nDrop);
|
||||
}
|
||||
|
||||
static char *dynamic_triggers_2(int iTid, int iArg){
|
||||
static char *dynamic_triggers_2(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
i64 iVal = 0;
|
||||
@@ -1352,6 +1373,7 @@ static char *dynamic_triggers_2(int iTid, int iArg){
|
||||
nDelete++;
|
||||
} while( iVal );
|
||||
}
|
||||
closedb(&err, &db);
|
||||
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("%d inserts, %d deletes", nInsert, nDelete);
|
||||
@@ -1376,15 +1398,16 @@ static void dynamic_triggers(int nMs){
|
||||
"CREATE TABLE t8(x, y);"
|
||||
"CREATE TABLE t9(x, y);"
|
||||
);
|
||||
closedb(&err, &db);
|
||||
|
||||
setstoptime(&err, nMs);
|
||||
|
||||
sqlite3_enable_shared_cache(1);
|
||||
launch_thread(&err, &threads, dynamic_triggers_2, 0);
|
||||
launch_thread(&err, &threads, dynamic_triggers_2, 0);
|
||||
sqlite3_enable_shared_cache(0);
|
||||
|
||||
sleep(2);
|
||||
sqlite3_enable_shared_cache(0);
|
||||
|
||||
launch_thread(&err, &threads, dynamic_triggers_2, 0);
|
||||
launch_thread(&err, &threads, dynamic_triggers_1, 0);
|
||||
@@ -1399,6 +1422,8 @@ static void dynamic_triggers(int nMs){
|
||||
#include "tt3_checkpoint.c"
|
||||
#include "tt3_index.c"
|
||||
#include "tt3_lookaside1.c"
|
||||
#include "tt3_vacuum.c"
|
||||
#include "tt3_stress.c"
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct ThreadTest {
|
||||
@@ -1420,35 +1445,31 @@ int main(int argc, char **argv){
|
||||
{ checkpoint_starvation_2, "checkpoint_starvation_2", 10000 },
|
||||
|
||||
{ create_drop_index_1, "create_drop_index_1", 10000 },
|
||||
{ lookaside1, "lookaside1", 10000 },
|
||||
{ lookaside1, "lookaside1", 10000 },
|
||||
{ vacuum1, "vacuum1", 10000 },
|
||||
{ stress1, "stress1", 10000 },
|
||||
{ stress2, "stress2", 60000 },
|
||||
};
|
||||
|
||||
int i;
|
||||
char *zTest = 0;
|
||||
int nTest = 0;
|
||||
int bTestfound = 0;
|
||||
int bPrefix = 0;
|
||||
|
||||
if( argc>2 ) goto usage;
|
||||
if( argc==2 ){
|
||||
zTest = argv[1];
|
||||
nTest = strlen(zTest);
|
||||
if( zTest[nTest-1]=='*' ){
|
||||
nTest--;
|
||||
bPrefix = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||
|
||||
for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
|
||||
char const *z = aTest[i].zTest;
|
||||
int n = strlen(z);
|
||||
if( !zTest || ((bPrefix || n==nTest) && 0==strncmp(zTest, z, nTest)) ){
|
||||
printf("Running %s for %d seconds...\n", z, aTest[i].nMs/1000);
|
||||
aTest[i].xTest(aTest[i].nMs);
|
||||
bTestfound++;
|
||||
if( argc>1 ){
|
||||
int iArg;
|
||||
for(iArg=1; iArg<argc; iArg++){
|
||||
if( 0==sqlite3_strglob(argv[iArg], z) ) break;
|
||||
}
|
||||
if( iArg==argc ) continue;
|
||||
}
|
||||
|
||||
printf("Running %s for %d seconds...\n", z, aTest[i].nMs/1000);
|
||||
aTest[i].xTest(aTest[i].nMs);
|
||||
bTestfound++;
|
||||
}
|
||||
if( bTestfound==0 ) goto usage;
|
||||
|
||||
@@ -1456,7 +1477,7 @@ int main(int argc, char **argv){
|
||||
return (nGlobalErr>0 ? 255 : 0);
|
||||
|
||||
usage:
|
||||
printf("Usage: %s [testname|testprefix*]\n", argv[0]);
|
||||
printf("Usage: %s [testname|testprefix*]...\n", argv[0]);
|
||||
printf("Available tests are:\n");
|
||||
for(i=0; i<sizeof(aTest)/sizeof(aTest[0]); i++){
|
||||
printf(" %s\n", aTest[i].zTest);
|
||||
|
||||
+53
-5
@@ -16,13 +16,17 @@
|
||||
** This test program runs on unix-like systems only. It uses pthreads.
|
||||
** To compile:
|
||||
**
|
||||
** gcc -o tt4 -I. threadtest4.c sqlite3.c -ldl -lpthread
|
||||
** gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread
|
||||
**
|
||||
** To run:
|
||||
**
|
||||
** ./tt4 10
|
||||
** ./a.out 10
|
||||
**
|
||||
** The argument is the number of threads.
|
||||
** 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>
|
||||
@@ -40,6 +44,7 @@
|
||||
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 */
|
||||
@@ -284,7 +289,7 @@ static void *worker_thread(void *pArg){
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
printf("worker %d startup\n", p->tid); fflush(stdout);
|
||||
for(iOuter=1; iOuter<=4; iOuter++){
|
||||
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);
|
||||
@@ -300,8 +305,48 @@ static void *worker_thread(void *pArg){
|
||||
}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( 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);
|
||||
@@ -362,6 +407,8 @@ int main(int argc, char **argv){
|
||||
"Options:\n"
|
||||
" --serialized\n"
|
||||
" --multithread\n"
|
||||
" --wal\n"
|
||||
" --trace\n"
|
||||
,argv[0]
|
||||
);
|
||||
exit(1);
|
||||
@@ -406,6 +453,7 @@ int main(int argc, char **argv){
|
||||
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;
|
||||
|
||||
@@ -66,7 +66,7 @@ static int checkpoint_starvation_walhook(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static char *checkpoint_starvation_reader(int iTid, int iArg){
|
||||
static char *checkpoint_starvation_reader(int iTid, void *pArg){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
|
||||
|
||||
+12
-12
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
|
||||
static char *create_drop_index_thread(int iTid, int iArg){
|
||||
static char *create_drop_index_thread(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
@@ -22,22 +22,22 @@ static char *create_drop_index_thread(int iTid, int iArg){
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
|
||||
sql_script(&err, &db,
|
||||
|
||||
"DROP INDEX IF EXISTS i1;"
|
||||
"DROP INDEX IF EXISTS i2;"
|
||||
"DROP INDEX IF EXISTS i3;"
|
||||
"DROP INDEX IF EXISTS i4;"
|
||||
|
||||
"CREATE INDEX IF NOT EXISTS i1 ON t1(a);"
|
||||
"CREATE INDEX IF NOT EXISTS i2 ON t1(b);"
|
||||
"CREATE INDEX IF NOT EXISTS i3 ON t1(c);"
|
||||
"CREATE INDEX IF NOT EXISTS i4 ON t1(d);"
|
||||
"CREATE INDEX IF NOT EXISTS i1 ON t11(a);"
|
||||
"CREATE INDEX IF NOT EXISTS i2 ON t11(b);"
|
||||
"CREATE INDEX IF NOT EXISTS i3 ON t11(c);"
|
||||
"CREATE INDEX IF NOT EXISTS i4 ON t11(d);"
|
||||
|
||||
"SELECT * FROM t1 ORDER BY a;"
|
||||
"SELECT * FROM t1 ORDER BY b;"
|
||||
"SELECT * FROM t1 ORDER BY c;"
|
||||
"SELECT * FROM t1 ORDER BY d;"
|
||||
"SELECT * FROM t11 ORDER BY a;"
|
||||
"SELECT * FROM t11 ORDER BY b;"
|
||||
"SELECT * FROM t11 ORDER BY c;"
|
||||
"SELECT * FROM t11 ORDER BY d;"
|
||||
);
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
|
||||
closedb(&err, &db);
|
||||
}
|
||||
@@ -53,9 +53,9 @@ static void create_drop_index_1(int nMs){
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
sql_script(&err, &db,
|
||||
"CREATE TABLE t1(a, b, c, d);"
|
||||
"CREATE TABLE t11(a, b, c, d);"
|
||||
"WITH data(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM data WHERE x<100) "
|
||||
"INSERT INTO t1 SELECT x,x,x,x FROM data;"
|
||||
"INSERT INTO t11 SELECT x,x,x,x FROM data;"
|
||||
);
|
||||
closedb(&err, &db);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
** that is suspected to exist at time of writing.
|
||||
*/
|
||||
|
||||
static char *lookaside1_thread_reader(int iTid, int iArg){
|
||||
static char *lookaside1_thread_reader(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
@@ -43,7 +43,7 @@ static char *lookaside1_thread_reader(int iTid, int iArg){
|
||||
return sqlite3_mprintf("ok");
|
||||
}
|
||||
|
||||
static char *lookaside1_thread_writer(int iTid, int iArg){
|
||||
static char *lookaside1_thread_writer(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
** 2014 December 9
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** Thread 1. CREATE and DROP a table.
|
||||
*/
|
||||
static char *stress_thread_1(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
while( !timetostop(&err) ){
|
||||
sql_script(&err, &db, "CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b)");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
sql_script(&err, &db, "DROP TABLE IF EXISTS t1");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
}
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("ok");
|
||||
}
|
||||
|
||||
/*
|
||||
** Thread 2. Open and close database connections.
|
||||
*/
|
||||
static char *stress_thread_2(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
while( !timetostop(&err) ){
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
sql_script(&err, &db, "SELECT * FROM sqlite_master;");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
closedb(&err, &db);
|
||||
}
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("ok");
|
||||
}
|
||||
|
||||
/*
|
||||
** Thread 3. Attempt many small SELECT statements.
|
||||
*/
|
||||
static char *stress_thread_3(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
while( !timetostop(&err) ){
|
||||
sql_script(&err, &db, "SELECT * FROM t1 ORDER BY a;");
|
||||
i1++;
|
||||
if( err.rc ) i2++;
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
clear_error(&err, SQLITE_ERROR);
|
||||
}
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("read t1 %d/%d attempts", i2, i1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Thread 5. Attempt INSERT statements.
|
||||
*/
|
||||
static char *stress_thread_4(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
while( !timetostop(&err) ){
|
||||
if( iArg ){
|
||||
closedb(&err, &db);
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
}
|
||||
sql_script(&err, &db,
|
||||
"WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop LIMIT 200) "
|
||||
"INSERT INTO t1 VALUES(randomblob(60), randomblob(60));"
|
||||
);
|
||||
i1++;
|
||||
if( err.rc ) i2++;
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
clear_error(&err, SQLITE_ERROR);
|
||||
}
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("wrote t1 %d/%d attempts", i2, i1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Thread 6. Attempt DELETE operations.
|
||||
*/
|
||||
static char *stress_thread_5(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int iArg = PTR2INT(pArg);
|
||||
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
while( !timetostop(&err) ){
|
||||
i64 i = (i1 % 4);
|
||||
if( iArg ){
|
||||
closedb(&err, &db);
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
}
|
||||
execsql(&err, &db, "DELETE FROM t1 WHERE (rowid % 4)==:i", &i);
|
||||
i1++;
|
||||
if( err.rc ) i2++;
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
}
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("deleted from t1 %d/%d attempts", i2, i1);
|
||||
}
|
||||
|
||||
|
||||
static void stress1(int nMs){
|
||||
Error err = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
setstoptime(&err, nMs);
|
||||
sqlite3_enable_shared_cache(1);
|
||||
|
||||
launch_thread(&err, &threads, stress_thread_1, 0);
|
||||
launch_thread(&err, &threads, stress_thread_1, 0);
|
||||
|
||||
launch_thread(&err, &threads, stress_thread_2, 0);
|
||||
launch_thread(&err, &threads, stress_thread_2, 0);
|
||||
|
||||
launch_thread(&err, &threads, stress_thread_3, 0);
|
||||
launch_thread(&err, &threads, stress_thread_3, 0);
|
||||
|
||||
launch_thread(&err, &threads, stress_thread_4, 0);
|
||||
launch_thread(&err, &threads, stress_thread_4, 0);
|
||||
|
||||
launch_thread(&err, &threads, stress_thread_5, 0);
|
||||
launch_thread(&err, &threads, stress_thread_5, (void*)1);
|
||||
|
||||
join_all_threads(&err, &threads);
|
||||
sqlite3_enable_shared_cache(0);
|
||||
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
***************************************************************************
|
||||
** Start of test case "stress2"
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** 1. CREATE TABLE statements.
|
||||
** 2. DROP TABLE statements.
|
||||
** 3. Small SELECT statements.
|
||||
** 4. Big SELECT statements.
|
||||
** 5. Small INSERT statements.
|
||||
** 6. Big INSERT statements.
|
||||
** 7. Small UPDATE statements.
|
||||
** 8. Big UPDATE statements.
|
||||
** 9. Small DELETE statements.
|
||||
** 10. Big DELETE statements.
|
||||
** 11. VACUUM.
|
||||
** 14. Integrity-check.
|
||||
** 17. Switch the journal mode from delete to wal and back again.
|
||||
** 19. Open and close database connections rapidly.
|
||||
*/
|
||||
|
||||
#define STRESS2_TABCNT 5 /* count1 in SDS test */
|
||||
|
||||
#define STRESS2_COUNT2 200 /* count2 in SDS test */
|
||||
#define STRESS2_COUNT3 57 /* count2 in SDS test */
|
||||
|
||||
static void stress2_workload1(Error *pErr, Sqlite *pDb, int i){
|
||||
int iTab = (i % (STRESS2_TABCNT-1)) + 1;
|
||||
sql_script_printf(pErr, pDb,
|
||||
"CREATE TABLE IF NOT EXISTS t%d(x PRIMARY KEY, y, z);", iTab
|
||||
);
|
||||
}
|
||||
|
||||
static void stress2_workload2(Error *pErr, Sqlite *pDb, int i){
|
||||
int iTab = (i % (STRESS2_TABCNT-1)) + 1;
|
||||
sql_script_printf(pErr, pDb, "DROP TABLE IF EXISTS t%d;", iTab);
|
||||
}
|
||||
|
||||
static void stress2_workload3(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script(pErr, pDb, "SELECT * FROM t0 WHERE z = 'small'");
|
||||
}
|
||||
|
||||
static void stress2_workload4(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script(pErr, pDb, "SELECT * FROM t0 WHERE z = 'big'");
|
||||
}
|
||||
|
||||
static void stress2_workload5(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script(pErr, pDb,
|
||||
"INSERT INTO t0 VALUES(hex(random()), hex(randomblob(200)), 'small');"
|
||||
);
|
||||
}
|
||||
|
||||
static void stress2_workload6(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script(pErr, pDb,
|
||||
"INSERT INTO t0 VALUES(hex(random()), hex(randomblob(57)), 'big');"
|
||||
);
|
||||
}
|
||||
|
||||
static void stress2_workload7(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script_printf(pErr, pDb,
|
||||
"UPDATE t0 SET y = hex(randomblob(200)) "
|
||||
"WHERE x LIKE hex((%d %% 5)) AND z='small';"
|
||||
,i
|
||||
);
|
||||
}
|
||||
static void stress2_workload8(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script_printf(pErr, pDb,
|
||||
"UPDATE t0 SET y = hex(randomblob(57)) "
|
||||
"WHERE x LIKE hex(%d %% 5) AND z='big';"
|
||||
,i
|
||||
);
|
||||
}
|
||||
|
||||
static void stress2_workload9(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script_printf(pErr, pDb,
|
||||
"DELETE FROM t0 WHERE x LIKE hex(%d %% 5) AND z='small';", i
|
||||
);
|
||||
}
|
||||
static void stress2_workload10(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script_printf(pErr, pDb,
|
||||
"DELETE FROM t0 WHERE x LIKE hex(%d %% 5) AND z='big';", i
|
||||
);
|
||||
}
|
||||
|
||||
static void stress2_workload11(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script(pErr, pDb, "VACUUM");
|
||||
}
|
||||
|
||||
static void stress2_workload14(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script(pErr, pDb, "PRAGMA integrity_check");
|
||||
}
|
||||
|
||||
static void stress2_workload17(Error *pErr, Sqlite *pDb, int i){
|
||||
sql_script_printf(pErr, pDb,
|
||||
"PRAGMA journal_mode = %q", (i%2) ? "delete" : "wal"
|
||||
);
|
||||
}
|
||||
|
||||
static char *stress2_workload19(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
const char *zDb = (const char*)pArg;
|
||||
while( !timetostop(&err) ){
|
||||
opendb(&err, &db, zDb, 0);
|
||||
sql_script(&err, &db, "SELECT * FROM sqlite_master;");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
closedb(&err, &db);
|
||||
}
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("ok");
|
||||
}
|
||||
|
||||
|
||||
typedef struct Stress2Ctx Stress2Ctx;
|
||||
struct Stress2Ctx {
|
||||
const char *zDb;
|
||||
void (*xProc)(Error*, Sqlite*, int);
|
||||
};
|
||||
|
||||
static char *stress2_thread_wrapper(int iTid, void *pArg){
|
||||
Stress2Ctx *pCtx = (Stress2Ctx*)pArg;
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
int cnt;
|
||||
opendb(&err, &db, pCtx->zDb, 0);
|
||||
for(cnt=0; err.rc==SQLITE_OK && cnt<STRESS2_TABCNT; cnt++){
|
||||
pCtx->xProc(&err, &db, i1);
|
||||
i2 += (err.rc==SQLITE_OK);
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
i1++;
|
||||
}
|
||||
closedb(&err, &db);
|
||||
}
|
||||
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("ok %d/%d", i2, i1);
|
||||
}
|
||||
|
||||
static void stress2_launch_thread_loop(
|
||||
Error *pErr, /* IN/OUT: Error code */
|
||||
Threadset *pThreads, /* Thread set */
|
||||
const char *zDb, /* Database name */
|
||||
void (*x)(Error*,Sqlite*,int) /* Run this until error or timeout */
|
||||
){
|
||||
Stress2Ctx *pCtx = sqlite3_malloc(sizeof(Stress2Ctx));
|
||||
pCtx->zDb = zDb;
|
||||
pCtx->xProc = x;
|
||||
launch_thread(pErr, pThreads, stress2_thread_wrapper, (void*)pCtx);
|
||||
}
|
||||
|
||||
static void stress2(int nMs){
|
||||
struct Stress2Task {
|
||||
void (*x)(Error*,Sqlite*,int);
|
||||
} aTask[] = {
|
||||
{ stress2_workload1 },
|
||||
{ stress2_workload2 },
|
||||
{ stress2_workload3 },
|
||||
{ stress2_workload4 },
|
||||
{ stress2_workload5 },
|
||||
{ stress2_workload6 },
|
||||
{ stress2_workload7 },
|
||||
{ stress2_workload8 },
|
||||
{ stress2_workload9 },
|
||||
{ stress2_workload10 },
|
||||
{ stress2_workload11 },
|
||||
{ stress2_workload14 },
|
||||
{ stress2_workload17 },
|
||||
};
|
||||
const char *zDb = "test.db";
|
||||
|
||||
int i;
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
/* To make sure the db file is empty before commencing */
|
||||
opendb(&err, &db, zDb, 1);
|
||||
sql_script(&err, &db,
|
||||
"CREATE TABLE IF NOT EXISTS t0(x PRIMARY KEY, y, z);"
|
||||
"CREATE INDEX IF NOT EXISTS i0 ON t0(y);"
|
||||
);
|
||||
closedb(&err, &db);
|
||||
|
||||
setstoptime(&err, nMs);
|
||||
sqlite3_enable_shared_cache(1);
|
||||
|
||||
for(i=0; i<sizeof(aTask)/sizeof(aTask[0]); i++){
|
||||
stress2_launch_thread_loop(&err, &threads, zDb, aTask[i].x);
|
||||
}
|
||||
launch_thread(&err, &threads, stress2_workload19, (void*)zDb);
|
||||
launch_thread(&err, &threads, stress2_workload19, (void*)zDb);
|
||||
|
||||
join_all_threads(&err, &threads);
|
||||
sqlite3_enable_shared_cache(0);
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
** 2014 December 9
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains multi-threaded tests that use shared-cache and
|
||||
** the VACUUM command.
|
||||
**
|
||||
** Tests:
|
||||
**
|
||||
** vacuum1
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
static char *vacuum1_thread_writer(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
i64 i = 0;
|
||||
|
||||
while( !timetostop(&err) ){
|
||||
i++;
|
||||
|
||||
/* Insert lots of rows. Then delete some. */
|
||||
execsql(&err, &db,
|
||||
"WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop WHERE i<100) "
|
||||
"INSERT INTO t1 SELECT randomblob(50), randomblob(2500) FROM loop"
|
||||
);
|
||||
|
||||
/* Delete lots of rows */
|
||||
execsql(&err, &db, "DELETE FROM t1 WHERE rowid = :i", &i);
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
|
||||
/* Select the rows */
|
||||
execsql(&err, &db, "SELECT * FROM t1 ORDER BY x");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
}
|
||||
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("ok");
|
||||
}
|
||||
|
||||
static char *vacuum1_thread_vacuumer(int iTid, void *pArg){
|
||||
Error err = {0}; /* Error code and message */
|
||||
Sqlite db = {0}; /* SQLite database connection */
|
||||
opendb(&err, &db, "test.db", 0);
|
||||
|
||||
do{
|
||||
sql_script(&err, &db, "VACUUM");
|
||||
clear_error(&err, SQLITE_LOCKED);
|
||||
}while( !timetostop(&err) );
|
||||
|
||||
closedb(&err, &db);
|
||||
print_and_free_err(&err);
|
||||
return sqlite3_mprintf("ok");
|
||||
}
|
||||
|
||||
static void vacuum1(int nMs){
|
||||
Error err = {0};
|
||||
Sqlite db = {0};
|
||||
Threadset threads = {0};
|
||||
|
||||
opendb(&err, &db, "test.db", 1);
|
||||
sql_script(&err, &db,
|
||||
"CREATE TABLE t1(x PRIMARY KEY, y BLOB);"
|
||||
"CREATE INDEX i1 ON t1(y);"
|
||||
);
|
||||
closedb(&err, &db);
|
||||
|
||||
setstoptime(&err, nMs);
|
||||
|
||||
sqlite3_enable_shared_cache(1);
|
||||
launch_thread(&err, &threads, vacuum1_thread_writer, 0);
|
||||
launch_thread(&err, &threads, vacuum1_thread_writer, 0);
|
||||
launch_thread(&err, &threads, vacuum1_thread_writer, 0);
|
||||
launch_thread(&err, &threads, vacuum1_thread_vacuumer, 0);
|
||||
join_all_threads(&err, &threads);
|
||||
sqlite3_enable_shared_cache(0);
|
||||
|
||||
print_and_free_err(&err);
|
||||
}
|
||||
Reference in New Issue
Block a user