mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Fix a problem where an SQLITE_BUSY in the checkpoint code was being treated as an IO error (abandoning, instead of just limiting, the checkpoint).
FossilOrigin-Name: 02c4040ce2b4c970b3dee09f7c9ad5a2a3a9aa49
This commit is contained in:
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sanother\sproblem\sin\stest_vfs.c.
|
||||
D 2010-06-03T19:10:09
|
||||
C Fix\sa\sproblem\swhere\san\sSQLITE_BUSY\sin\sthe\scheckpoint\scode\swas\sbeing\streated\sas\san\sIO\serror\s(abandoning,\sinstead\sof\sjust\slimiting,\sthe\scheckpoint).
|
||||
D 2010-06-04T10:37:06
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -207,7 +207,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
|
||||
F src/test_vfs.c 0f0242f29584537845cf0e0dfc04ece0b357b857
|
||||
F src/test_vfs.c 6203bc7d88a95a093ceb2c372252317b3154b315
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
||||
@@ -224,7 +224,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||
F src/wal.c be73c9a8a3027a7bba1229dc09890927b992da45
|
||||
F src/wal.c 453811af926fe12eacea41b4ea02ee1a2d2f004b
|
||||
F src/wal.h 4ace25262452d17e7d3ec970c89ee17794004008
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
|
||||
@@ -763,13 +763,13 @@ F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test bfec61450b47cdf09f7d2269f9e9967683b8b0fc
|
||||
F test/wal2.test 1dcbbe59ab662bebb859bb1ede83143f8a39814e
|
||||
F test/wal3.test cac89168c8f8a8679f1fb5234624d5699a84b2f0
|
||||
F test/wal3.test 535867201f4e5eccc459dbfdbb43e1b9555fd30a
|
||||
F test/wal_common.tcl 3e953ae60919281688ea73e4d0aa0e1bc94becd9
|
||||
F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
|
||||
F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
|
||||
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
||||
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
|
||||
F test/walfault.test 0cd672eb059d98ef07714f64371fd7d4d1ebb642
|
||||
F test/walfault.test 4c412eae947aea5f58d5c616a4d8740f034e49d1
|
||||
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
|
||||
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
@@ -817,7 +817,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P fcbf7cf189506e43fc2f0820aedffb195038d3a9
|
||||
R e093d2af0534cd33e5ed13655be56b08
|
||||
P df7d59899ceb2743764b0433cb68f4bc33f16344
|
||||
R 1a3cb251079fbc88fab0e8991c692f47
|
||||
U dan
|
||||
Z e9eec85577950a5d26e2b23744407a2d
|
||||
Z 13abdffaf01f3e682d39faa8c6e78666
|
||||
|
@@ -1 +1 @@
|
||||
df7d59899ceb2743764b0433cb68f4bc33f16344
|
||||
02c4040ce2b4c970b3dee09f7c9ad5a2a3a9aa49
|
@@ -596,7 +596,8 @@ static int tvfsShmGet(
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_SHMGET_MASK ){
|
||||
tvfsExecTcl(p, "xShmGet",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,
|
||||
Tcl_NewIntObj(reqMapSize)
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
|
26
src/wal.c
26
src/wal.c
@@ -1299,14 +1299,10 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
int i; /* Iterator variable */
|
||||
int nFinal; /* Number of unindexed entries */
|
||||
u8 *aTmp; /* Temp space used by merge-sort */
|
||||
int rc; /* Return code of walIndexMap() */
|
||||
u8 *aSpace; /* Surplus space on the end of the allocation */
|
||||
|
||||
/* Make sure the wal-index is mapped into local memory */
|
||||
rc = walIndexMap(pWal, walMappingSize(pWal->hdr.mxFrame));
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pWal->pWiData && pWal->szWIndex>=walMappingSize(pWal->hdr.mxFrame) );
|
||||
|
||||
/* This routine only runs while holding SQLITE_SHM_CHECKPOINT. No other
|
||||
** thread is able to write to shared memory while this routine is
|
||||
@@ -1360,7 +1356,6 @@ static void walIteratorFree(WalIterator *p){
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Copy as much content as we can from the WAL back into the database file
|
||||
** in response to an sqlite3_wal_checkpoint() request or the equivalent.
|
||||
@@ -1411,14 +1406,13 @@ static int walCheckpoint(
|
||||
/* Allocate the iterator */
|
||||
rc = walIteratorInit(pWal, &pIter);
|
||||
if( rc!=SQLITE_OK || pWal->hdr.mxFrame==0 ){
|
||||
walIteratorFree(pIter);
|
||||
return rc;
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
|
||||
/*** TODO: Move this test out to the caller. Make it an assert() here ***/
|
||||
if( pWal->hdr.szPage!=nBuf ){
|
||||
walIteratorFree(pIter);
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
@@ -1432,17 +1426,16 @@ static int walCheckpoint(
|
||||
assert( pInfo==walCkptInfo(pWal) );
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( y>0 && (mxSafeFrame==0 || mxSafeFrame>=y) ){
|
||||
if( y<=pWal->hdr.mxFrame
|
||||
&& walLockExclusive(pWal, WAL_READ_LOCK(i), 1)==SQLITE_OK
|
||||
){
|
||||
if( y>0 && mxSafeFrame>=y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->aReadMark[i] = 0;
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
mxSafeFrame = y-1;
|
||||
}else{
|
||||
walIteratorFree(pIter);
|
||||
return rc;
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1488,6 +1481,7 @@ static int walCheckpoint(
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
walcheckpoint_out:
|
||||
walIteratorFree(pIter);
|
||||
return rc;
|
||||
}
|
||||
|
@@ -109,5 +109,88 @@ for {set i 1} {$i < 20} {incr i} {
|
||||
db2 close
|
||||
}
|
||||
|
||||
db close
|
||||
foreach code [list {
|
||||
proc code2 {tcl} { uplevel #0 $tcl }
|
||||
proc code3 {tcl} { uplevel #0 $tcl }
|
||||
set tn singleproc
|
||||
} {
|
||||
set ::code2_chan [launch_testfixture]
|
||||
set ::code3_chan [launch_testfixture]
|
||||
proc code2 {tcl} { testfixture $::code2_chan $tcl }
|
||||
proc code3 {tcl} { testfixture $::code3_chan $tcl }
|
||||
set tn multiproc
|
||||
}] {
|
||||
file delete -force test.db test.db-wal test.db-journal
|
||||
sqlite3 db test.db
|
||||
eval $code
|
||||
|
||||
# Open connections [db2] and [db3]. Depending on which iteration this
|
||||
# is, the connections may be created in this interpreter, or in
|
||||
# interpreters running in other OS processes. As such, the [db2] and [db3]
|
||||
# commands should only be accessed within [code2] and [code3] blocks,
|
||||
# respectively.
|
||||
#
|
||||
code2 { sqlite3 db2 test.db ; db2 eval { PRAGMA journal_mode = WAL } }
|
||||
code3 { sqlite3 db3 test.db ; db3 eval { PRAGMA journal_mode = WAL } }
|
||||
|
||||
# Shorthand commands. Execute SQL using database connection [db], [db2]
|
||||
# or [db3]. Return the results.
|
||||
#
|
||||
proc sql {sql} { db eval $sql }
|
||||
proc sql2 {sql} { code2 [list db2 eval $sql] }
|
||||
proc sql3 {sql} { code3 [list db3 eval $sql] }
|
||||
|
||||
do_test wal3-2.$tn.1 {
|
||||
sql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = OFF;
|
||||
PRAGMA journal_mode = WAL;
|
||||
}
|
||||
sql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 one}
|
||||
do_test wal3-2.$tn.2 {
|
||||
sql2 {
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
BEGIN;
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {2 two}
|
||||
do_test wal3-2.$tn.3 {
|
||||
sql3 {
|
||||
CREATE TABLE t3(a, b);
|
||||
INSERT INTO t3 VALUES(3, 'three');
|
||||
BEGIN;
|
||||
SELECT * FROM t3;
|
||||
}
|
||||
} {3 three}
|
||||
|
||||
# Try to checkpoint the database using [db]. It should be possible to
|
||||
# checkpoint everything except the frames added by [db3] (checkpointing
|
||||
# these frames would clobber the snapshot currently being used by [db2]).
|
||||
#
|
||||
do_test wal3-2.$tn.4 {
|
||||
sql {
|
||||
COMMIT;
|
||||
PRAGMA wal_checkpoint;
|
||||
}
|
||||
} {}
|
||||
do_test wal3-2.$tn.5 {
|
||||
file size test.db
|
||||
} [expr 3*1024]
|
||||
|
||||
|
||||
catch { db close }
|
||||
catch { code2 { db2 close } }
|
||||
catch { code3 { db3 close } }
|
||||
catch { close $::code2_chan }
|
||||
catch { close $::code3_chan }
|
||||
}
|
||||
finish_test
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
|
||||
@@ -321,82 +322,5 @@ do_faultsim_test walfault-9 -prep {
|
||||
if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" }
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# When a database is checkpointed, SQLite does the following:
|
||||
#
|
||||
# 1. xShmLock(CHECKPOINT) to lock the WAL.
|
||||
# 2. xShmGet(-1) to get a mapping to read the wal-index header.
|
||||
# 3. If the mapping obtained in (2) is not large enough to cover the
|
||||
# entire wal-index, call xShmGet(nReq) to get a larger mapping.
|
||||
# 4. Do the checkpoint.
|
||||
# 5. Release the lock and mapping.
|
||||
#
|
||||
# This test case tests the outcome of an IO error in step 2.
|
||||
#
|
||||
proc walfault_10_vfs_cb {method args} {
|
||||
switch -- $::shm_state {
|
||||
0 { return SQLITE_OK }
|
||||
1 {
|
||||
if {$method == "xShmGet"} {
|
||||
set ::wal_index [tvfs shm [lindex $args 0]]
|
||||
tvfs shm [lindex $args 0] [string range $::wal_index 0 65535]
|
||||
set ::shm_state 2
|
||||
}
|
||||
}
|
||||
2 {
|
||||
if {$method == "xShmGet"} {
|
||||
tvfs shm [lindex $args 0] $::wal_index
|
||||
return SQLITE_IOERR
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
do_test walfault-10.1 {
|
||||
set ::shm_state 0
|
||||
testvfs tvfs
|
||||
tvfs script walfault_10_vfs_cb
|
||||
|
||||
sqlite3 db test.db -vfs tvfs
|
||||
sqlite3 db2 test.db -vfs tvfs
|
||||
|
||||
execsql {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA wal_autocheckpoint = 0;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
}
|
||||
} {wal 0}
|
||||
do_test walfault-10.2 {
|
||||
execsql {
|
||||
PRAGMA wal_autocheckpoint = 0;
|
||||
BEGIN;
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */
|
||||
INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */
|
||||
COMMIT;
|
||||
} db2
|
||||
} {0}
|
||||
do_test walfault-10.3 {
|
||||
set ::shm_state 1
|
||||
catchsql { PRAGMA wal_checkpoint } db2
|
||||
} {1 {disk I/O error}}
|
||||
set ::shm_state 0
|
||||
db close
|
||||
db2 close
|
||||
tvfs delete
|
||||
unset -nocomplain ::wal_index ::shm_state
|
||||
|
||||
finish_test
|
||||
|
||||
|
Reference in New Issue
Block a user