1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Make calls to sqlite3BtreeRollbackStmt() no-ops when passed a Btree* handle that does not have an open statement transaction. Ticket #3718. (CVS 6342)

FossilOrigin-Name: a1bb1aef0e06140a2d5d5e4b6c10c73ce95c89e0
This commit is contained in:
danielk1977
2009-03-12 14:43:27 +00:00
parent 6fa0fe13f0
commit 20736d82e2
6 changed files with 195 additions and 21 deletions

View File

@ -1,5 +1,5 @@
C Begin\spurging\sdirty\spages\sfrom\sthe\scache\sonce\s90%\sof\sthe\scache\sis\sdirty\s(insteadof\swaiting\suntil\sit\sis\s100%\sdirty).\sThis\simproves\sperformance\sin\ssome\scircumstances\sby\seffectively\sreserving\s10%\sof\sthe\sconfigured\spage-cache\sfor\sfrequently\sreused\sread-only\spages.\s(CVS\s6341) C Make\scalls\sto\ssqlite3BtreeRollbackStmt()\sno-ops\swhen\spassed\sa\sBtree*\shandle\sthat\sdoes\snot\shave\san\sopen\sstatement\stransaction.\sTicket\s#3718.\s(CVS\s6342)
D 2009-03-05T14:59:40 D 2009-03-12T14:43:28
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in d64baddbf55cdf33ff030e14da837324711a4ef7 F Makefile.in d64baddbf55cdf33ff030e14da837324711a4ef7
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -103,7 +103,7 @@ F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
F src/backup.c 2d3f31148d7b086c5c72d9edcd04fc2751b0aa6e F src/backup.c 2d3f31148d7b086c5c72d9edcd04fc2751b0aa6e
F src/bitvec.c 44f7059ac1f874d364b34af31b9617e52223ba75 F src/bitvec.c 44f7059ac1f874d364b34af31b9617e52223ba75
F src/btmutex.c 341502bc496dc0840dcb00cde65680fb0e85c3ab F src/btmutex.c 341502bc496dc0840dcb00cde65680fb0e85c3ab
F src/btree.c ec710abc5a71eefba93d2b99330ff2eacd941e08 F src/btree.c 6e7501d7a207dcc15b099e67231bc8cc86ef7fe9
F src/btree.h 96a019c9f28da38e79940512d7800e419cd8c702 F src/btree.h 96a019c9f28da38e79940512d7800e419cd8c702
F src/btreeInt.h 0a4884e6152d7cae9c741e91b830064c19fd2c05 F src/btreeInt.h 0a4884e6152d7cae9c741e91b830064c19fd2c05
F src/build.c 741240c8d6a54201fa8757db1ee6efba71be59a2 F src/build.c 741240c8d6a54201fa8757db1ee6efba71be59a2
@ -493,7 +493,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 47e9e5bbec8509023479d54ceb71c9d05a95308a F test/printf.test 47e9e5bbec8509023479d54ceb71c9d05a95308a
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/quick.test b7acd5b3df583391979d9f9edf98aa85fc95a3f6 F test/quick.test d93ab4f1eee87b89fddbe938e2f093ce33e7b46a
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
@ -556,8 +556,9 @@ F test/temptrigger.test 03093be9967942623232dfdf2a63b832d4e0e4fa
F test/tester.tcl 66546f6766029384360b24cacb3896376c5f5f69 F test/tester.tcl 66546f6766029384360b24cacb3896376c5f5f69
F test/thread001.test 06c45ed9597d478e7bbdc2a8937e1ebea2a20a32 F test/thread001.test 06c45ed9597d478e7bbdc2a8937e1ebea2a20a32
F test/thread002.test 3c03900f03fd2fe8e2fbb1bbdef7fa8206fdb7ad F test/thread002.test 3c03900f03fd2fe8e2fbb1bbdef7fa8206fdb7ad
F test/thread003.test 6d360c15afe7f6ef6186801d2cb8407bccbe3aa3 F test/thread003.test a8bc91af1d9d524148dd84e4d6a196ba17521e08
F test/thread004.test 9d8ea6a9b0d62d35ad0b967e010d723ed99f614a F test/thread004.test 9d8ea6a9b0d62d35ad0b967e010d723ed99f614a
F test/thread005.test 5141b3ee8debc99549f62512265a50be36d1b6a6
F test/thread1.test 862dd006d189e8b0946935db17399dcac2f8ef91 F test/thread1.test 862dd006d189e8b0946935db17399dcac2f8ef91
F test/thread2.test 91f105374f18a66e73a3254c28fe7c77af69bdea F test/thread2.test 91f105374f18a66e73a3254c28fe7c77af69bdea
F test/thread_common.tcl 047f80288b5e1e86bed181097d67e640f1a54a74 F test/thread_common.tcl 047f80288b5e1e86bed181097d67e640f1a54a74
@ -703,7 +704,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P d0b2015f1caf2fc60ec82bd8e760f7b61befa3b4 P 823fe7f5551e121e211d1ede606a7ce7487ffe0d
R 039bb14c767370b62d0edeb68de61ac0 R 0a620faaa60e0f8f26633feb77199541
U danielk1977 U danielk1977
Z 7a03629d714ccf300df7a819fca83b05 Z e6301158e9a3d6dc90886b4a779a1ded

View File

@ -1 +1 @@
823fe7f5551e121e211d1ede606a7ce7487ffe0d a1bb1aef0e06140a2d5d5e4b6c10c73ce95c89e0

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btree.c,v 1.571 2009/03/05 04:20:32 shane Exp $ ** $Id: btree.c,v 1.572 2009/03/12 14:43:28 danielk1977 Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information. ** See the header comment on "btreeInt.h" for additional information.
@ -2822,18 +2822,16 @@ int sqlite3BtreeBeginStmt(Btree *p){
** subtransaction is active, this is a no-op. ** subtransaction is active, this is a no-op.
*/ */
int sqlite3BtreeCommitStmt(Btree *p){ int sqlite3BtreeCommitStmt(Btree *p){
int rc; int rc = SQLITE_OK;
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
pBt->db = p->db; pBt->db = p->db;
assert( pBt->readOnly==0 ); if( p->inTrans==TRANS_WRITE && pBt->inStmt ){
if( pBt->inStmt ){
int iStmtpoint = p->db->nSavepoint; int iStmtpoint = p->db->nSavepoint;
assert( pBt->readOnly==0 );
rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint); rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
}else{ pBt->inStmt = 0;
rc = SQLITE_OK;
} }
pBt->inStmt = 0;
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return rc; return rc;
} }
@ -2851,9 +2849,9 @@ int sqlite3BtreeRollbackStmt(Btree *p){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
pBt->db = p->db; pBt->db = p->db;
assert( pBt->readOnly==0 ); if( p->inTrans==TRANS_WRITE && pBt->inStmt ){
if( pBt->inStmt ){
int iStmtpoint = p->db->nSavepoint; int iStmtpoint = p->db->nSavepoint;
assert( pBt->readOnly==0 );
rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_ROLLBACK, iStmtpoint); rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_ROLLBACK, iStmtpoint);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint); rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);

View File

@ -6,7 +6,7 @@
#*********************************************************************** #***********************************************************************
# This file runs all tests. # This file runs all tests.
# #
# $Id: quick.test,v 1.93 2009/02/26 07:15:59 danielk1977 Exp $ # $Id: quick.test,v 1.94 2009/03/12 14:43:28 danielk1977 Exp $
proc lshift {lvar} { proc lshift {lvar} {
upvar $lvar l upvar $lvar l
@ -86,6 +86,7 @@ set EXCLUDE {
thread002.test thread002.test
thread003.test thread003.test
thread004.test thread004.test
thread005.test
trans2.test trans2.test
vacuum3.test vacuum3.test

View File

@ -12,7 +12,7 @@
# This file contains tests that attempt to break the pcache module # This file contains tests that attempt to break the pcache module
# by bombarding it with simultaneous requests from multiple threads. # by bombarding it with simultaneous requests from multiple threads.
# #
# $Id: thread003.test,v 1.6 2009/02/12 17:06:41 drh Exp $ # $Id: thread003.test,v 1.7 2009/03/12 14:43:28 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
@ -158,7 +158,7 @@ do_test thread003.3 {
# sqlite3_release_memory() over and over again. # sqlite3_release_memory() over and over again.
# #
set nSecond 30 set nSecond 30
puts "Starting thread003.3 (should run for ~$nSecond seconds)" puts "Starting thread003.4 (should run for ~$nSecond seconds)"
unset -nocomplain finished(1) unset -nocomplain finished(1)
unset -nocomplain finished(2) unset -nocomplain finished(2)
do_test thread003.4 { do_test thread003.4 {

174
test/thread005.test Normal file
View File

@ -0,0 +1,174 @@
# 2009 March 11
#
# 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.
#
#***********************************************************************
#
# Test a race-condition that shows up in shared-cache mode.
#
# $Id: thread005.test,v 1.1 2009/03/12 14:43:28 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !mutex||!shared_cache {
return
}
source $testdir/thread_common.tcl
if {[info commands sqlthread] eq ""} {
return
}
#-------------------------------------------------------------------------
# This test tries to exercise a race-condition that existed in shared-cache
# mode at one point. The test uses two threads; each has a database connection
# open on the same shared cache. The schema of the database is:
#
# CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
#
# One thread is a reader and the other thread a reader and a writer. The
# writer thread repeats the following transaction as fast as possible:
#
# BEGIN;
# DELETE FROM t1 WHERE a = (SELECT max(a) FROM t1);
# INSERT INTO t1 VALUES(NULL, NULL);
# UPDATE t1 SET b = a WHERE a = (SELECT max(a) FROM t1);
# SELECT count(*) FROM t1 WHERE b IS NULL;
# COMMIT;
#
# The reader thread does the following over and over as fast as possible:
#
# BEGIN;
# SELECT count(*) FROM t1 WHERE b IS NULL;
# COMMIT;
#
# The test runs for 20 seconds or until one of the "SELECT count(*)"
# statements returns a non-zero value. If an SQLITE_LOCKED error occurs,
# the connection issues a ROLLBACK immediately to abandon the current
# transaction.
#
# If everything is working correctly, the "SELECT count(*)" statements
# should never return a value other than 0. The "INSERT" statement
# executed by the writer adds a row with "b IS NULL" to the table, but
# the subsequent UPDATE statement sets its "b" value to an integer
# immediately afterwards.
#
# However, before the race-condition was fixed, if the reader's SELECT
# statement hit an error (say an SQLITE_LOCKED) at the same time as the
# writer was executing the UPDATE statement, then it could incorrectly
# rollback the statement-transaction belonging to the UPDATE statement.
# The UPDATE statement would still be reported as successful to the user,
# but it would have no effect on the database contents.
#
# Note that it has so far only proved possible to hit this race-condition
# when using an ATTACHed database. There doesn't seem to be any reason
# for this, other than that operating on an ATTACHed database means there
# are a few more mutex grabs and releases during the window of time open
# for the race-condition. Maybe this encourages the scheduler to context
# switch or something...
#
# Use shared-cache mode for this test.
#
db close
set ::enable_shared_cache [sqlite3_enable_shared_cache]
sqlite3_enable_shared_cache 1
file delete -force test.db test2.db
do_test thread005-1.1 {
sqlite3 db test.db
execsql { ATTACH 'test2.db' AS aux }
execsql {
CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b UNIQUE);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
}
db close
} {}
set ThreadProgram {
proc execsql {zSql {db {}}} {
if {$db eq ""} {set db $::DB}
set lRes [list]
set rc SQLITE_OK
while {$rc=="SQLITE_OK" && $zSql ne ""} {
set STMT [sqlite3_prepare_v2 $db $zSql -1 zSql]
while {[set rc [sqlite3_step $STMT]] eq "SQLITE_ROW"} {
for {set i 0} {$i < [sqlite3_column_count $STMT]} {incr i} {
lappend lRes [sqlite3_column_text $STMT 0]
}
}
set rc [sqlite3_finalize $STMT]
}
if {$rc != "SQLITE_OK"} { error "$rc [sqlite3_errmsg $db]" }
return $lRes
}
if {$isWriter} {
set Sql {
BEGIN;
DELETE FROM t1 WHERE a = (SELECT max(a) FROM t1);
INSERT INTO t1 VALUES(NULL, NULL);
UPDATE t1 SET b = a WHERE a = (SELECT max(a) FROM t1);
SELECT count(*) FROM t1 WHERE b IS NULL;
COMMIT;
}
} else {
set Sql {
BEGIN;
SELECT count(*) FROM t1 WHERE b IS NULL;
COMMIT;
}
}
set ::DB [sqlite3_open test.db]
execsql { ATTACH 'test2.db' AS aux }
set result "ok"
set finish [expr [clock_seconds]+5]
while {$result eq "ok" && [clock_seconds] < $finish} {
set rc [catch {execsql $Sql} msg]
if {$rc} {
if {[string match "SQLITE_LOCKED*" $msg]} {
catch { execsql ROLLBACK }
} else {
error $msg
}
} elseif {$msg ne "0"} {
set result "failed"
}
}
sqlite3_close $::DB
set result
}
puts "Running thread-tests for ~20 seconds"
thread_spawn finished(0) {set isWriter 0} $ThreadProgram
thread_spawn finished(1) {set isWriter 1} $ThreadProgram
if {![info exists finished(0)]} { vwait finished(0) }
if {![info exists finished(1)]} { vwait finished(1) }
do_test thread005-1.2 {
list $finished(0) $finished(1)
} {ok ok}
do_test thread005-1.3 {
sqlite3 db test.db
execsql { ATTACH 'test2.db' AS aux }
execsql { SELECT count(*) FROM t1 WHERE b IS NULL }
} {0}
sqlite3_enable_shared_cache $::enable_shared_cache
finish_test