Change blocking-checkpoint tests so that they run once using "PRAGMA wal_checkpoint" and once using calls to sqlite3_wal_checkpoint_v2(). Also fix edge cases surrounding the output variables set by wal_checkpoint_v2().
FossilOrigin-Name: 5a4b6652cf3780ffed6fe0fe669e8090b0b71e81
This commit is contained in:
parent
2fe88b7ca4
commit
9c5e3680df
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
||||
C Ensure\sfts4aux\scan\shandle\sa\stable\sname\sin\ssingle\sor\sdouble\squotes\sas\sa\sconstructor\sargument.
|
||||
D 2011-02-05T15:47:12.471
|
||||
C Change\sblocking-checkpoint\stests\sso\sthat\sthey\srun\sonce\susing\s"PRAGMA\swal_checkpoint"\sand\sonce\susing\scalls\sto\ssqlite3_wal_checkpoint_v2().\sAlso\sfix\sedge\scases\ssurrounding\sthe\soutput\svariables\sset\sby\swal_checkpoint_v2().
|
||||
D 2011-02-07T15:12:12.557
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in de6498556d536ae60bb8bb10e8c1ba011448658c
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -142,7 +142,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
|
||||
F src/main.c 1b04ef67eb03d026c8cc2d438c61635163153c24
|
||||
F src/main.c bc1c822dafa9a6c6c43179c0cbd3f1ce686a84c6
|
||||
F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
|
||||
@ -184,7 +184,7 @@ F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 549859dc2c143f3deb6a92636a2d27973652c164
|
||||
F src/test1.c 771407a49ae199241f0efb7055634e4a1899c026
|
||||
F src/test1.c ddbfff546e22e5c31204c973fdd805a4eda3e208
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
@ -238,7 +238,7 @@ F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
|
||||
F src/vdbemem.c c011228c6fb1b5df924e4584765b16bde863c9c6
|
||||
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
|
||||
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
|
||||
F src/wal.c 8704a563b37c0c48b6a65d49da5d5656568abfc6
|
||||
F src/wal.c aca10a60655e103fc8630a75345000f43c6d47ca
|
||||
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c f4915ac03e5e42c8416b35ca3ba34af841c00d12
|
||||
@ -662,7 +662,7 @@ F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test f66a8f26dcd390c115bb732a2ea4638ab8204b13
|
||||
F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
|
||||
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
|
||||
@ -845,7 +845,7 @@ F test/wal.test f060cae4b2164c4375109a8f803873187234661d
|
||||
F test/wal2.test 57a218446654ed3e3592c925762633c1d1e85636
|
||||
F test/wal3.test ec87d9dd9e9cebabed4024064e8ff531d336ead2
|
||||
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
|
||||
F test/wal5.test 1f99651d856c8b9e1376781c981d1b903e93a478
|
||||
F test/wal5.test 3fef990d256cd9e95e9ad97e5dfdf3f150743fce
|
||||
F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8
|
||||
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
|
||||
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
|
||||
@ -906,7 +906,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P dc511e60a65232a7087e12ff40b63506cf37a634
|
||||
R 8b6bef7500d37a03d9cad23f74319954
|
||||
P 929d62e496bb36a3ee0e19ec4609329d79aaeddc
|
||||
R 5272b64137511ea0a87063bfd04f9af5
|
||||
U dan
|
||||
Z 659706e533fac6825c1f6da67c2f77f1
|
||||
Z 8b5f17a482d9dd489ee7270bd10b0d2b
|
||||
|
@ -1 +1 @@
|
||||
929d62e496bb36a3ee0e19ec4609329d79aaeddc
|
||||
5a4b6652cf3780ffed6fe0fe669e8090b0b71e81
|
@ -1356,6 +1356,10 @@ int sqlite3_wal_checkpoint_v2(
|
||||
int rc; /* Return code */
|
||||
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
|
||||
|
||||
/* Initialize the output variables to -1 in case an error occurs. */
|
||||
if( pnLog ) *pnLog = -1;
|
||||
if( pnCkpt ) *pnCkpt = -1;
|
||||
|
||||
if( eMode!=SQLITE_CHECKPOINT_PASSIVE
|
||||
&& eMode!=SQLITE_CHECKPOINT_FULL
|
||||
&& eMode!=SQLITE_CHECKPOINT_RESTART
|
||||
@ -1416,6 +1420,8 @@ int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
|
||||
int bBusy = 0; /* True if SQLITE_BUSY has been encountered */
|
||||
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
assert( !pnLog || *pnLog==-1 );
|
||||
assert( !pnCkpt || *pnCkpt==-1 );
|
||||
|
||||
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
|
||||
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
|
||||
|
68
src/test1.c
68
src/test1.c
@ -5186,6 +5186,73 @@ static int test_wal_checkpoint(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_wal_checkpoint_v2 db MODE ?NAME?
|
||||
**
|
||||
** This command calls the wal_checkpoint_v2() function with the specified
|
||||
** mode argument (passive, full or restart). If present, the database name
|
||||
** NAME is passed as the second argument to wal_checkpoint_v2(). If it the
|
||||
** NAME argument is not present, a NULL pointer is passed instead.
|
||||
**
|
||||
** If wal_checkpoint_v2() returns any value other than SQLITE_BUSY or
|
||||
** SQLITE_OK, then this command returns TCL_ERROR. The Tcl result is set
|
||||
** to the error message obtained from sqlite3_errmsg().
|
||||
**
|
||||
** Otherwise, this command returns a list of three integers. The first integer
|
||||
** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers
|
||||
** are the values returned via the output paramaters by wal_checkpoint_v2() -
|
||||
** the number of frames in the log and the number of frames in the log
|
||||
** that have been checkpointed.
|
||||
*/
|
||||
static int test_wal_checkpoint_v2(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
char *zDb = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
|
||||
int eMode;
|
||||
int nLog = -555;
|
||||
int nCkpt = -555;
|
||||
Tcl_Obj *pRet;
|
||||
|
||||
const char * aMode[] = { "passive", "full", "restart", 0 };
|
||||
assert( SQLITE_CHECKPOINT_PASSIVE==0 );
|
||||
assert( SQLITE_CHECKPOINT_FULL==1 );
|
||||
assert( SQLITE_CHECKPOINT_RESTART==2 );
|
||||
|
||||
if( objc!=3 && objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( objc==4 ){
|
||||
zDb = Tcl_GetString(objv[3]);
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
|
||||
|| Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pRet = Tcl_NewObj();
|
||||
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(rc==SQLITE_BUSY?1:0));
|
||||
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nLog));
|
||||
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCkpt));
|
||||
Tcl_SetObjResult(interp, pRet);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_sqlite3_log ?SCRIPT?
|
||||
*/
|
||||
@ -5572,6 +5639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_unlock_notify", test_unlock_notify, 0 },
|
||||
#endif
|
||||
{ "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 },
|
||||
{ "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 },
|
||||
{ "test_sqlite3_log", test_sqlite3_log, 0 },
|
||||
{ "print_explain_query_plan", test_print_eqp, 0 },
|
||||
};
|
||||
|
16
src/wal.c
16
src/wal.c
@ -1623,8 +1623,7 @@ static int walCheckpoint(
|
||||
int (*xBusyCall)(void*), /* Function to call when busy */
|
||||
void *pBusyArg, /* Context argument for xBusyHandler */
|
||||
int sync_flags, /* Flags for OsSync() (or 0) */
|
||||
u8 *zBuf, /* Temporary buffer to use */
|
||||
int *pnCkpt /* Total frames checkpointed */
|
||||
u8 *zBuf /* Temporary buffer to use */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
int szPage; /* Database page-size */
|
||||
@ -1641,7 +1640,6 @@ static int walCheckpoint(
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
pInfo = walCkptInfo(pWal);
|
||||
if( pnCkpt ) *pnCkpt = pInfo->nBackfill;
|
||||
if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
|
||||
|
||||
/* Allocate the iterator */
|
||||
@ -1727,7 +1725,6 @@ static int walCheckpoint(
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->nBackfill = mxSafeFrame;
|
||||
if( pnCkpt ) *pnCkpt = mxSafeFrame;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2764,12 +2761,17 @@ int sqlite3WalCheckpoint(
|
||||
}
|
||||
|
||||
/* Copy data from the log to the database file. */
|
||||
if( rc==SQLITE_OK && pWal->hdr.mxFrame ){
|
||||
if( walPagesize(pWal)!=nBuf ){
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
|
||||
}
|
||||
|
||||
/* If no error occurred, set the output variables. */
|
||||
if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
|
||||
if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
|
||||
rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags,zBuf,pnCkpt);
|
||||
if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ db_swap test.db2 test.db
|
||||
do_catchsql_test 6.4 { SELECT * FROM t1 } {0 {1 2 3 4}}
|
||||
do_catchsql_test 6.5 { SELECT * FROM t2 } {1 {no such table: t2}}
|
||||
|
||||
do_execsql_test 6.6 { PRAGMA wal_checkpoint } {0 -1 -1}
|
||||
do_execsql_test 6.6 { PRAGMA wal_checkpoint } {0 0 0}
|
||||
|
||||
db_swap test.db2 test.db
|
||||
do_catchsql_test 6.7 { SELECT * FROM t1 } {1 {no such table: t1}}
|
||||
|
521
test/wal5.test
521
test/wal5.test
@ -25,235 +25,316 @@ proc db_page_count {{file test.db}} { expr [file size $file] / 1024 }
|
||||
proc wal_page_count {{file test.db}} { wal_frame_count ${file}-wal 1024 }
|
||||
|
||||
|
||||
do_multiclient_test tn {
|
||||
|
||||
|
||||
set ::nBusyHandler 0
|
||||
set ::busy_handler_script ""
|
||||
proc busyhandler {n} {
|
||||
incr ::nBusyHandler
|
||||
eval $::busy_handler_script
|
||||
return 0
|
||||
}
|
||||
|
||||
proc reopen_all {} {
|
||||
code1 {db close}
|
||||
code2 {db2 close}
|
||||
code3 {db3 close}
|
||||
code1 {sqlite3 db test.db}
|
||||
code2 {sqlite3 db2 test.db}
|
||||
code3 {sqlite3 db3 test.db}
|
||||
sql1 { PRAGMA synchronous = NORMAL }
|
||||
code1 { db busy busyhandler }
|
||||
}
|
||||
|
||||
do_test 1.$tn.1 {
|
||||
reopen_all
|
||||
sql1 {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
CREATE TABLE t1(x, y);
|
||||
PRAGMA journal_mode = WAL;
|
||||
INSERT INTO t1 VALUES(1, zeroblob(1200));
|
||||
INSERT INTO t1 VALUES(2, zeroblob(1200));
|
||||
INSERT INTO t1 VALUES(3, zeroblob(1200));
|
||||
}
|
||||
expr [file size test.db] / 1024
|
||||
} {2}
|
||||
|
||||
# Have connection 2 grab a read-lock on the current snapshot.
|
||||
do_test 1.$tn.2 { sql2 { BEGIN; SELECT x FROM t1 } } {1 2 3}
|
||||
|
||||
# Attempt a checkpoint.
|
||||
do_test 1.$tn.3 {
|
||||
sql1 { PRAGMA wal_checkpoint }
|
||||
list [db_page_count] [wal_page_count]
|
||||
} {5 9}
|
||||
|
||||
# Write to the db again. The log cannot wrap because of the lock still
|
||||
# held by connection 2. The busy-handler has not yet been invoked.
|
||||
do_test 1.$tn.4 {
|
||||
sql1 { INSERT INTO t1 VALUES(4, zeroblob(1200)) }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {5 12 0}
|
||||
|
||||
# Now do a blocking-checkpoint. Set the busy-handler up so that connection
|
||||
# 2 releases its lock on the 6th invocation. The checkpointer should then
|
||||
# proceed to checkpoint the entire log file. Next write should go to the
|
||||
# start of the log file.
|
||||
#
|
||||
set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
|
||||
do_test 1.$tn.5 {
|
||||
sql1 { PRAGMA wal_checkpoint = RESTART }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {6 12 6}
|
||||
do_test 1.$tn.6 {
|
||||
set ::nBusyHandler 0
|
||||
sql1 { INSERT INTO t1 VALUES(5, zeroblob(1200)) }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {6 12 0}
|
||||
|
||||
do_test 1.$tn.7 {
|
||||
reopen_all
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {7 0 0}
|
||||
|
||||
do_test 1.$tn.8 { sql2 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5}
|
||||
do_test 1.$tn.9 {
|
||||
sql1 { INSERT INTO t1 VALUES(6, zeroblob(1200)) }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {7 5 0}
|
||||
do_test 1.$tn.10 { sql3 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5 6}
|
||||
|
||||
set ::busy_handler_script {
|
||||
if {$n==5} { sql2 COMMIT }
|
||||
if {$n==6} { set ::db_file_size [db_page_count] }
|
||||
if {$n==7} { sql3 COMMIT }
|
||||
}
|
||||
do_test 1.$tn.11 {
|
||||
sql1 { PRAGMA wal_checkpoint = RESTART }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {10 5 8}
|
||||
do_test 1.$tn.12 { set ::db_file_size } 10
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This block of tests explores checkpoint operations on more than one
|
||||
# database file.
|
||||
# A checkpoint may be requested either using the C API or by executing
|
||||
# an SQL PRAGMA command. To test both methods, all tests in this file are
|
||||
# run twice - once using each method to request checkpoints.
|
||||
#
|
||||
proc setup_and_attach_aux {} {
|
||||
sql1 { ATTACH 'test.db2' AS aux }
|
||||
sql2 { ATTACH 'test.db2' AS aux }
|
||||
sql3 { ATTACH 'test.db2' AS aux }
|
||||
sql1 {
|
||||
PRAGMA main.page_size=1024; PRAGMA main.journal_mode=WAL;
|
||||
PRAGMA aux.page_size=1024; PRAGMA aux.journal_mode=WAL;
|
||||
}
|
||||
}
|
||||
foreach {testprefix do_wal_checkpoint} {
|
||||
|
||||
proc file_page_counts {} {
|
||||
list [db_page_count test.db ] \
|
||||
[wal_page_count test.db ] \
|
||||
[db_page_count test.db2] \
|
||||
[wal_page_count test.db2]
|
||||
}
|
||||
|
||||
# Test that executing "PRAGMA wal_checkpoint" checkpoints all attached
|
||||
# databases, not just the main db.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
do_test 2.1.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
}
|
||||
} {}
|
||||
do_test 2.2.$tn.2 { file_page_counts } {1 5 1 5}
|
||||
do_test 2.1.$tn.3 { sql1 { PRAGMA wal_checkpoint } } {0 5 5}
|
||||
do_test 2.1.$tn.4 { file_page_counts } {2 5 2 5}
|
||||
}
|
||||
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
do_test 2.2.$tn.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
}
|
||||
} {}
|
||||
do_test 2.2.$tn.2 { file_page_counts } {1 5 1 7}
|
||||
do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
|
||||
do_test 2.2.$tn.4 { sql1 { PRAGMA wal_checkpoint = RESTART } } {1 5 5}
|
||||
do_test 2.2.$tn.5 { file_page_counts } {2 5 2 7}
|
||||
}
|
||||
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
do_test 2.3.$tn.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
}
|
||||
} {}
|
||||
do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5}
|
||||
do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
|
||||
do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
|
||||
do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
|
||||
do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
|
||||
do_test 2.3.$tn.7 { sql1 { PRAGMA wal_checkpoint = FULL } } {1 7 5}
|
||||
do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
|
||||
}
|
||||
|
||||
# Check that checkpoints block on the correct locks. And respond correctly
|
||||
# if they cannot obtain those locks. There are three locks that a checkpoint
|
||||
# may block on (in the following order):
|
||||
#
|
||||
# 1. The writer lock: FULL and RESTART checkpoints block until any writer
|
||||
# process releases its lock.
|
||||
#
|
||||
# 2. Readers using part of the log file. FULL and RESTART checkpoints block
|
||||
# until readers using part (but not all) of the log file have finished.
|
||||
#
|
||||
# 3. Readers using any of the log file. After copying data into the
|
||||
# database file, RESTART checkpoints block until readers using any part
|
||||
# of the log file have finished.
|
||||
#
|
||||
# This test case involves running a checkpoint while there exist other
|
||||
# processes holding all three types of locks.
|
||||
#
|
||||
foreach {tn1 checkpoint busy_on ckpt_expected expected} {
|
||||
1 PASSIVE - {0 5 5} -
|
||||
2 TYPO - {0 5 5} -
|
||||
|
||||
3 FULL - {0 7 7} 2
|
||||
4 FULL 1 {1 5 5} 1
|
||||
5 FULL 2 {1 7 5} 2
|
||||
6 FULL 3 {0 7 7} 2
|
||||
|
||||
7 RESTART - {0 7 7} 3
|
||||
8 RESTART 1 {1 5 5} 1
|
||||
9 RESTART 2 {1 7 5} 2
|
||||
10 RESTART 3 {1 7 7} 3
|
||||
|
||||
} {
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
|
||||
proc busyhandler {x} {
|
||||
set ::max_busyhandler $x
|
||||
if {$::busy_on!="-" && $x==$::busy_on} { return 1 }
|
||||
switch -- $x {
|
||||
1 { sql2 "COMMIT ; BEGIN ; SELECT * FROM t1" }
|
||||
2 { sql3 "COMMIT" }
|
||||
3 { sql2 "COMMIT" }
|
||||
wal5-pragma {
|
||||
proc do_wal_checkpoint { dbhandle args } {
|
||||
array set a $args
|
||||
foreach key [array names a] {
|
||||
if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
|
||||
}
|
||||
|
||||
set sql "PRAGMA "
|
||||
if {[info exists a(-db)]} { append sql "$a(-db)." }
|
||||
append sql "wal_checkpoint"
|
||||
if {[info exists a(-mode)]} { append sql " = $a(-mode)" }
|
||||
|
||||
uplevel [list $dbhandle eval $sql]
|
||||
}
|
||||
}
|
||||
|
||||
wal5-capi {
|
||||
proc do_wal_checkpoint { dbhandle args } {
|
||||
set a(-mode) passive
|
||||
array set a $args
|
||||
foreach key [array names a] {
|
||||
if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
|
||||
}
|
||||
|
||||
if {$a(-mode)!="restart" && $a(-mode)!="full"} { set a(-mode) passive }
|
||||
|
||||
set cmd [list sqlite3_wal_checkpoint_v2 $dbhandle $a(-mode)]
|
||||
if {[info exists a(-db)]} { lappend sql $a(-db) }
|
||||
|
||||
uplevel $cmd
|
||||
}
|
||||
}
|
||||
} {
|
||||
|
||||
eval $do_wal_checkpoint
|
||||
|
||||
do_multiclient_test tn {
|
||||
|
||||
set ::nBusyHandler 0
|
||||
set ::busy_handler_script ""
|
||||
proc busyhandler {n} {
|
||||
incr ::nBusyHandler
|
||||
eval $::busy_handler_script
|
||||
return 0
|
||||
}
|
||||
set ::max_busyhandler -
|
||||
|
||||
do_test 2.4.$tn1.$tn.1 {
|
||||
|
||||
proc reopen_all {} {
|
||||
code1 {db close}
|
||||
code2 {db2 close}
|
||||
code3 {db3 close}
|
||||
|
||||
code1 {sqlite3 db test.db}
|
||||
code2 {sqlite3 db2 test.db}
|
||||
code3 {sqlite3 db3 test.db}
|
||||
|
||||
sql1 { PRAGMA synchronous = NORMAL }
|
||||
code1 { db busy busyhandler }
|
||||
}
|
||||
|
||||
do_test 1.$tn.1 {
|
||||
reopen_all
|
||||
sql1 {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
CREATE TABLE t1(x, y);
|
||||
PRAGMA journal_mode = WAL;
|
||||
INSERT INTO t1 VALUES(1, zeroblob(1200));
|
||||
INSERT INTO t1 VALUES(2, zeroblob(1200));
|
||||
INSERT INTO t1 VALUES(3, zeroblob(1200));
|
||||
}
|
||||
expr [file size test.db] / 1024
|
||||
} {2}
|
||||
|
||||
# Have connection 2 grab a read-lock on the current snapshot.
|
||||
do_test 1.$tn.2 { sql2 { BEGIN; SELECT x FROM t1 } } {1 2 3}
|
||||
|
||||
# Attempt a checkpoint.
|
||||
do_test 1.$tn.3 {
|
||||
code1 { do_wal_checkpoint db }
|
||||
list [db_page_count] [wal_page_count]
|
||||
} {5 9}
|
||||
|
||||
# Write to the db again. The log cannot wrap because of the lock still
|
||||
# held by connection 2. The busy-handler has not yet been invoked.
|
||||
do_test 1.$tn.4 {
|
||||
sql1 { INSERT INTO t1 VALUES(4, zeroblob(1200)) }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {5 12 0}
|
||||
|
||||
# Now do a blocking-checkpoint. Set the busy-handler up so that connection
|
||||
# 2 releases its lock on the 6th invocation. The checkpointer should then
|
||||
# proceed to checkpoint the entire log file. Next write should go to the
|
||||
# start of the log file.
|
||||
#
|
||||
set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
|
||||
do_test 1.$tn.5 {
|
||||
code1 { do_wal_checkpoint db -mode restart }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {6 12 6}
|
||||
do_test 1.$tn.6 {
|
||||
set ::nBusyHandler 0
|
||||
sql1 { INSERT INTO t1 VALUES(5, zeroblob(1200)) }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {6 12 0}
|
||||
|
||||
do_test 1.$tn.7 {
|
||||
reopen_all
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {7 0 0}
|
||||
|
||||
do_test 1.$tn.8 { sql2 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5}
|
||||
do_test 1.$tn.9 {
|
||||
sql1 { INSERT INTO t1 VALUES(6, zeroblob(1200)) }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {7 5 0}
|
||||
do_test 1.$tn.10 { sql3 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5 6}
|
||||
|
||||
set ::busy_handler_script {
|
||||
if {$n==5} { sql2 COMMIT }
|
||||
if {$n==6} { set ::db_file_size [db_page_count] }
|
||||
if {$n==7} { sql3 COMMIT }
|
||||
}
|
||||
do_test 1.$tn.11 {
|
||||
code1 { do_wal_checkpoint db -mode restart }
|
||||
list [db_page_count] [wal_page_count] $::nBusyHandler
|
||||
} {10 5 8}
|
||||
do_test 1.$tn.12 { set ::db_file_size } 10
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This block of tests explores checkpoint operations on more than one
|
||||
# database file.
|
||||
#
|
||||
proc setup_and_attach_aux {} {
|
||||
sql1 { ATTACH 'test.db2' AS aux }
|
||||
sql2 { ATTACH 'test.db2' AS aux }
|
||||
sql3 { ATTACH 'test.db2' AS aux }
|
||||
sql1 {
|
||||
PRAGMA main.page_size=1024; PRAGMA main.journal_mode=WAL;
|
||||
PRAGMA aux.page_size=1024; PRAGMA aux.journal_mode=WAL;
|
||||
}
|
||||
}
|
||||
|
||||
proc file_page_counts {} {
|
||||
list [db_page_count test.db ] \
|
||||
[wal_page_count test.db ] \
|
||||
[db_page_count test.db2] \
|
||||
[wal_page_count test.db2]
|
||||
}
|
||||
|
||||
# Test that executing "PRAGMA wal_checkpoint" checkpoints all attached
|
||||
# databases, not just the main db. In capi mode, check that this is
|
||||
# true if a NULL pointer is passed to wal_checkpoint_v2() in place of a
|
||||
# database name.
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
do_test 2.1.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
}
|
||||
sql2 { BEGIN; INSERT INTO t1 VALUES(3, 4) }
|
||||
sql3 { BEGIN; SELECT * FROM t1 }
|
||||
} {1 2}
|
||||
|
||||
do_test 2.4.$tn1.$tn.2 {
|
||||
code1 { db busy busyhandler }
|
||||
sql1 "PRAGMA wal_checkpoint = $checkpoint"
|
||||
} $ckpt_expected
|
||||
do_test 2.4.$tn1.$tn.3 { set ::max_busyhandler } $expected
|
||||
} {}
|
||||
do_test 2.2.$tn.2 { file_page_counts } {1 5 1 5}
|
||||
do_test 2.1.$tn.3 { code1 { do_wal_checkpoint db } } {0 5 5}
|
||||
do_test 2.1.$tn.4 { file_page_counts } {2 5 2 5}
|
||||
}
|
||||
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
do_test 2.2.$tn.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
}
|
||||
} {}
|
||||
do_test 2.2.$tn.2 { file_page_counts } {1 5 1 7}
|
||||
do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
|
||||
do_test 2.2.$tn.4 { code1 { do_wal_checkpoint db -mode restart } } {1 5 5}
|
||||
do_test 2.2.$tn.5 { file_page_counts } {2 5 2 7}
|
||||
}
|
||||
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
do_test 2.3.$tn.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 2);
|
||||
}
|
||||
} {}
|
||||
do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5}
|
||||
do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
|
||||
do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
|
||||
do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
|
||||
do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7}
|
||||
do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5}
|
||||
do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7}
|
||||
}
|
||||
|
||||
# Check that checkpoints block on the correct locks. And respond correctly
|
||||
# if they cannot obtain those locks. There are three locks that a checkpoint
|
||||
# may block on (in the following order):
|
||||
#
|
||||
# 1. The writer lock: FULL and RESTART checkpoints block until any writer
|
||||
# process releases its lock.
|
||||
#
|
||||
# 2. Readers using part of the log file. FULL and RESTART checkpoints block
|
||||
# until readers using part (but not all) of the log file have finished.
|
||||
#
|
||||
# 3. Readers using any of the log file. After copying data into the
|
||||
# database file, RESTART checkpoints block until readers using any part
|
||||
# of the log file have finished.
|
||||
#
|
||||
# This test case involves running a checkpoint while there exist other
|
||||
# processes holding all three types of locks.
|
||||
#
|
||||
foreach {tn1 checkpoint busy_on ckpt_expected expected} {
|
||||
1 PASSIVE - {0 5 5} -
|
||||
2 TYPO - {0 5 5} -
|
||||
|
||||
3 FULL - {0 7 7} 2
|
||||
4 FULL 1 {1 5 5} 1
|
||||
5 FULL 2 {1 7 5} 2
|
||||
6 FULL 3 {0 7 7} 2
|
||||
|
||||
7 RESTART - {0 7 7} 3
|
||||
8 RESTART 1 {1 5 5} 1
|
||||
9 RESTART 2 {1 7 5} 2
|
||||
10 RESTART 3 {1 7 7} 3
|
||||
|
||||
} {
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
|
||||
proc busyhandler {x} {
|
||||
set ::max_busyhandler $x
|
||||
if {$::busy_on!="-" && $x==$::busy_on} { return 1 }
|
||||
switch -- $x {
|
||||
1 { sql2 "COMMIT ; BEGIN ; SELECT * FROM t1" }
|
||||
2 { sql3 "COMMIT" }
|
||||
3 { sql2 "COMMIT" }
|
||||
}
|
||||
return 0
|
||||
}
|
||||
set ::max_busyhandler -
|
||||
|
||||
do_test 2.4.$tn1.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
sql2 { BEGIN; INSERT INTO t1 VALUES(3, 4) }
|
||||
sql3 { BEGIN; SELECT * FROM t1 }
|
||||
} {1 2}
|
||||
|
||||
do_test 2.4.$tn1.$tn.2 {
|
||||
code1 { db busy busyhandler }
|
||||
code1 { do_wal_checkpoint db -mode [string tolower $checkpoint] }
|
||||
} $ckpt_expected
|
||||
do_test 2.4.$tn1.$tn.3 { set ::max_busyhandler } $expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do_multiclient_test tn {
|
||||
|
||||
code1 $do_wal_checkpoint
|
||||
code2 $do_wal_checkpoint
|
||||
code3 $do_wal_checkpoint
|
||||
|
||||
do_test 3.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = normal;
|
||||
CREATE TABLE t1(x, y);
|
||||
}
|
||||
|
||||
sql2 { PRAGMA journal_mode }
|
||||
sql3 { PRAGMA journal_mode }
|
||||
} {wal}
|
||||
|
||||
do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}
|
||||
|
||||
do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}
|
||||
|
||||
do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}
|
||||
|
||||
code1 {db close}
|
||||
code2 {db2 close}
|
||||
code3 {db3 close}
|
||||
|
||||
code1 {sqlite3 db test.db}
|
||||
code2 {sqlite3 db2 test.db}
|
||||
code3 {sqlite3 db3 test.db}
|
||||
|
||||
do_test 3.$tn.5 { sql3 { PRAGMA journal_mode } } {wal}
|
||||
|
||||
do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user