Fix a problem whereby following an IO error in CommitPhaseTwo() of a multi-file transaction the b-tree layer could be left in TRANS_WRITE state, causing problems later on.
FossilOrigin-Name: dbe569a099c2855480e35c0cc4d9332821ad80da
This commit is contained in:
parent
0fd7d86081
commit
60939d0ade
0
install-sh
Normal file → Executable file
0
install-sh
Normal file → Executable file
30
manifest
30
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\sa\sproblem\sin\sthe\sunix\sVFS\simplementation\sof\sxNextSystemCall().\sAlso\ssome\stypos\sthat\sprevent\scompilation\swhen\sHAVE_POSIX_FALLOCATE\sis\sdefined.
|
||||
D 2011-03-29T10:04:23
|
||||
C Fix\sa\sproblem\swhereby\sfollowing\san\sIO\serror\sin\sCommitPhaseTwo()\sof\sa\smulti-file\stransaction\sthe\sb-tree\slayer\scould\sbe\sleft\sin\sTRANS_WRITE\sstate,\scausing\sproblems\slater\son.
|
||||
D 2011-03-29T15:40:55.407
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -99,7 +99,7 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk 7e4d4d0433c9cbfd906c6451a7cc50310a8f4555
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
@ -118,11 +118,11 @@ F src/alter.c 6a0c176e64a34929a4436048066a84ef4f1445b3
|
||||
F src/analyze.c a038162344265ac21dfb24b3fcc06c666ebb9c07
|
||||
F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 6728d6d48d55b449af76a3e51c0808849cb32a2e
|
||||
F src/backup.c 537f89c7ef5021cb580f31f782e556ffffcb2ed1
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c 43302cc4f3de6479b90fa6bb271b65d86333d00e
|
||||
F src/btree.h e2f2cd9933bf30724f53ffa12c4c5a3a864bbd6e
|
||||
F src/btree.c 2b9c81ff64da339a67dda4f94c0d763627be0b67
|
||||
F src/btree.h 8d36f774ec4b1d0027b8966f8c03d9a72a518c14
|
||||
F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4
|
||||
F src/build.c 6c490fe14dedb094a202f559e3b29a276abffcf8
|
||||
F src/callback.c 5069f224882cbdccd559f591271d28d7f37745bc
|
||||
@ -220,7 +220,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c b2b3aef993253395da25d564a920014cc3673f09
|
||||
F src/test_syscall.c bbdc88d0a5e42d0c35eaff8ae7ec86e8867f5543
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
|
||||
@ -236,7 +236,7 @@ F src/vdbe.c e3f37ca0afdd72e883475e2a32a06167df2810d0
|
||||
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
|
||||
F src/vdbeInt.h e1c6254641168507d25b46affb6dfb53c782f553
|
||||
F src/vdbeapi.c a09ad9164cafc505250d5dd6b69660c960f1308c
|
||||
F src/vdbeaux.c cfd3f3ac674691ba1166ceb9a2698b0d00b2ef91
|
||||
F src/vdbeaux.c 9211dfa7d79d94d4e50714bfd0497ff3588a739d
|
||||
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
|
||||
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
|
||||
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
|
||||
@ -459,7 +459,7 @@ F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
|
||||
F test/fts3fault2.test f275554f4a4fc7abf71e2975a9d6f4693f390526
|
||||
F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d
|
||||
F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
|
||||
F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
@ -604,7 +604,7 @@ F test/permutations.test 5b2a4cb756ffb2407cb4743163668d1d769febb6
|
||||
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota.test ddafe133653093eb9a99ccd6264884ae43f9c9b8
|
||||
@ -672,8 +672,8 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
|
||||
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
|
||||
F test/syscall.test 2f3e4e2cf91c3b870c4eac37f62c61208a199403
|
||||
F test/sysfault.test 63144f0000167f12676adccee2a0db45eb5c2314
|
||||
F test/syscall.test 5ae4b3d4f2aca2ef3c3a777f619e0c6b0cf592aa
|
||||
F test/sysfault.test 359ea90a58788c867ac0f9cb52431f56ed975672
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
@ -919,7 +919,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 7270f80ac5dd17b979f1f790b2dfcf811866c1dc
|
||||
R 667989871349daf241bf6e2f9ef88c3d
|
||||
P bc6cce81565b17f886478bd51500bba2ed11ec1d
|
||||
R 4ba5c752b69008d11d64e0bac5b06138
|
||||
U dan
|
||||
Z e094d9a9a392624fe79d654e33f9ed32
|
||||
Z d0374b5c64afa57baa2ab5bac0bd8f73
|
||||
|
@ -1 +1 @@
|
||||
bc6cce81565b17f886478bd51500bba2ed11ec1d
|
||||
dbe569a099c2855480e35c0cc4d9332821ad80da
|
@ -488,7 +488,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
|
||||
/* Finish committing the transaction to the destination database. */
|
||||
if( SQLITE_OK==rc
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest))
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
|
||||
){
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
@ -502,7 +502,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
if( bCloseTrans ){
|
||||
TESTONLY( int rc2 );
|
||||
TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
|
||||
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc);
|
||||
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
|
||||
assert( rc2==SQLITE_OK );
|
||||
}
|
||||
|
||||
|
17
src/btree.c
17
src/btree.c
@ -3160,10 +3160,21 @@ static void btreeEndTransaction(Btree *p){
|
||||
** the rollback journal (which causes the transaction to commit) and
|
||||
** drop locks.
|
||||
**
|
||||
** Normally, if an error occurs while the pager layer is attempting to
|
||||
** finalize the underlying journal file, this function returns an error and
|
||||
** the upper layer will attempt a rollback. However, if the second argument
|
||||
** is non-zero then this b-tree transaction is part of a multi-file
|
||||
** transaction. In this case, the transaction has already been committed
|
||||
** (by deleting a master journal file) and the caller will ignore this
|
||||
** functions return code. So, even if an error occurs in the pager layer,
|
||||
** reset the b-tree objects internal state to indicate that the write
|
||||
** transaction has been closed. This is quite safe, as the pager will have
|
||||
** transitioned to the error state.
|
||||
**
|
||||
** This will release the write lock on the database file. If there
|
||||
** are no active cursors, it also releases the read lock.
|
||||
*/
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree *p){
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
|
||||
|
||||
if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
|
||||
sqlite3BtreeEnter(p);
|
||||
@ -3178,7 +3189,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
assert( pBt->nTransaction>0 );
|
||||
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc!=SQLITE_OK && bCleanup==0 ){
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
}
|
||||
@ -3198,7 +3209,7 @@ int sqlite3BtreeCommit(Btree *p){
|
||||
sqlite3BtreeEnter(p);
|
||||
rc = sqlite3BtreeCommitPhaseOne(p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeCommitPhaseTwo(p);
|
||||
rc = sqlite3BtreeCommitPhaseTwo(p, 0);
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
|
@ -87,7 +87,7 @@ int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
int sqlite3BtreeBeginStmt(Btree*,int);
|
||||
|
@ -120,7 +120,7 @@ struct TestSyscallArray {
|
||||
/* 3 */ { "getcwd", (sqlite3_syscall_ptr)ts_getcwd, 0, 0, 0 },
|
||||
/* 4 */ { "stat", (sqlite3_syscall_ptr)ts_stat, 0, 0, 0 },
|
||||
/* 5 */ { "fstat", (sqlite3_syscall_ptr)ts_fstat, 0, 0, 0 },
|
||||
/* 6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, 0, 0 },
|
||||
/* 6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 },
|
||||
/* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, 0, 0 },
|
||||
/* 8 */ { "read", (sqlite3_syscall_ptr)ts_read, 0, 0, 0 },
|
||||
/* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 },
|
||||
@ -152,7 +152,6 @@ struct TestSyscallArray {
|
||||
#define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig)
|
||||
#define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
|
||||
|
||||
|
||||
/*
|
||||
** This function is called exactly once from within each invocation of a
|
||||
** system call wrapper in this file. It returns 1 if the function should
|
||||
@ -264,7 +263,7 @@ static int ts_fstat(int fd, struct stat *p){
|
||||
** A wrapper around ftruncate().
|
||||
*/
|
||||
static int ts_ftruncate(int fd, off_t n){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("ftruncate") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_ftruncate(fd, n);
|
||||
@ -533,6 +532,8 @@ static int test_syscall_errno(
|
||||
int i;
|
||||
} aErrno[] = {
|
||||
{ "EACCES", EACCES },
|
||||
{ "EINTR", EINTR },
|
||||
{ "EIO", EIO },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -1703,7 +1703,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = sqlite3BtreeCommitPhaseTwo(pBt);
|
||||
rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -1835,7 +1835,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeCommitPhaseTwo(pBt);
|
||||
sqlite3BtreeCommitPhaseTwo(pBt, 1);
|
||||
}
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
|
@ -14,6 +14,9 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix fts3fault2
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
do_test 1.0 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(x);
|
||||
|
0
test/progress.test
Executable file → Normal file
0
test/progress.test
Executable file → Normal file
@ -59,4 +59,53 @@ set syscall_list [list \
|
||||
if {[test_syscall exists fallocate]} {lappend syscall_list fallocate}
|
||||
do_test 3.1 { test_syscall list } $syscall_list
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This test verifies that if a call to open() fails and errno is set to
|
||||
# EINTR, the call is retried. If it succeeds, execution continues as if
|
||||
# nothing happened.
|
||||
#
|
||||
test_syscall reset
|
||||
forcedelete test.db2
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t2(x, y);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
}
|
||||
|
||||
db_save_and_close
|
||||
test_syscall install open
|
||||
foreach jrnl [list wal delete] {
|
||||
for {set i 1} {$i < 20} {incr i} {
|
||||
db_restore_and_reopen
|
||||
test_syscall fault $i 0
|
||||
test_syscall errno open EINTR
|
||||
|
||||
do_test 4.2.$jrnl.$i {
|
||||
sqlite3 db test.db
|
||||
execsql { ATTACH 'test.db2' AS aux }
|
||||
execsql "PRAGMA main.journal_mode = $jrnl"
|
||||
execsql "PRAGMA aux.journal_mode = $jrnl"
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8);
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { ATTACH 'test.db2' AS aux }
|
||||
execsql {
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {1 2 5 6 3 4 7 8}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -66,5 +66,79 @@ do_faultsim_test 1 -faults vfsfault-* -prep {
|
||||
{1 {attempt to write a readonly database}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that a single EINTR error does not affect processing.
|
||||
#
|
||||
proc vfsfault_install {} {
|
||||
test_syscall reset
|
||||
test_syscall install {open ftruncate close}
|
||||
}
|
||||
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db test.db
|
||||
do_test 2.setup {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
|
||||
INSERT INTO t1 VALUES('abc', 'def', 'ghi');
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
CREATE TABLE aux.t2(x);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
|
||||
do_faultsim_test 2.1 -faults vfsfault-transient -prep {
|
||||
catch { db close }
|
||||
faultsim_restore
|
||||
} -body {
|
||||
test_syscall errno open EINTR
|
||||
test_syscall errno ftruncate EINTR
|
||||
test_syscall errno close EINTR
|
||||
|
||||
sqlite3 db test.db
|
||||
set res [db eval {
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
SELECT * FROM t1;
|
||||
PRAGMA journal_mode = truncate;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
|
||||
UPDATE t2 SET x = 2;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}]
|
||||
db close
|
||||
set res
|
||||
} -test {
|
||||
faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}}
|
||||
}
|
||||
|
||||
do_faultsim_test 2.2 -faults vfsfault-* -prep {
|
||||
catch { db close }
|
||||
faultsim_restore
|
||||
} -body {
|
||||
sqlite3 db test.db
|
||||
set res [db eval {
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
SELECT * FROM t1;
|
||||
PRAGMA journal_mode = truncate;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
|
||||
UPDATE t2 SET x = 2;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}]
|
||||
db close
|
||||
set res
|
||||
} -test {
|
||||
faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}} \
|
||||
{1 {unable to open database file}} \
|
||||
{1 {unable to open database: test.db2}} \
|
||||
{1 {attempt to write a readonly database}} \
|
||||
{1 {disk I/O error}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user