Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make calls to sqlite3BtreeRollbackStmt() no-ops when passed a Btree* handle that does not have an open statement transaction. Ticket #3718. (CVS 6342) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
a1bb1aef0e06140a2d5d5e4b6c10c73c |
User & Date: | danielk1977 2009-03-12 14:43:28.000 |
Context
2009-03-12
| ||
15:43 | Avoid fts3 crash on (MATCH '""') expressions. Ticket #3717. (CVS 6343) (check-in: 03679857a3 user: danielk1977 tags: trunk) | |
14:43 | Make calls to sqlite3BtreeRollbackStmt() no-ops when passed a Btree* handle that does not have an open statement transaction. Ticket #3718. (CVS 6342) (check-in: a1bb1aef0e user: danielk1977 tags: trunk) | |
2009-03-05
| ||
14:59 | Begin purging dirty pages from the cache once 90% of the cache is dirty (insteadof waiting until it is 100% dirty). This improves performance in some circumstances by effectively reserving 10% of the configured page-cache for frequently reused read-only pages. (CVS 6341) (check-in: 823fe7f555 user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* ** $Id: btree.c,v 1.572 2009/03/12 14:43:28 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
2818 2819 2820 2821 2822 2823 2824 | } /* ** Commit the statment subtransaction currently in progress. If no ** subtransaction is active, this is a no-op. */ int sqlite3BtreeCommitStmt(Btree *p){ | | < | > < | < < | > | 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 | } /* ** Commit the statment subtransaction currently in progress. If no ** subtransaction is active, this is a no-op. */ int sqlite3BtreeCommitStmt(Btree *p){ int rc = SQLITE_OK; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); pBt->db = p->db; if( p->inTrans==TRANS_WRITE && pBt->inStmt ){ int iStmtpoint = p->db->nSavepoint; assert( pBt->readOnly==0 ); rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint); pBt->inStmt = 0; } sqlite3BtreeLeave(p); return rc; } /* ** Rollback the active statement subtransaction. If no subtransaction ** is active this routine is a no-op. ** ** All cursors will be invalidated by this operation. Any attempt ** to use a cursor that was open at the beginning of this operation ** will result in an error. */ int sqlite3BtreeRollbackStmt(Btree *p){ int rc = SQLITE_OK; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); pBt->db = p->db; if( p->inTrans==TRANS_WRITE && pBt->inStmt ){ int iStmtpoint = p->db->nSavepoint; assert( pBt->readOnly==0 ); rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_ROLLBACK, iStmtpoint); if( rc==SQLITE_OK ){ rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint); } pBt->inStmt = 0; } sqlite3BtreeLeave(p); |
︙ | ︙ |
Changes to test/quick.test.
1 2 3 4 5 6 7 8 | # # 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 runs all tests. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # # 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 runs all tests. # # $Id: quick.test,v 1.94 2009/03/12 14:43:28 danielk1977 Exp $ proc lshift {lvar} { upvar $lvar l set ret [lindex $l 0] set l [lrange $l 1 end] return $ret } |
︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 93 94 95 | speed4p.test sqllimits1.test tkt2686.test thread001.test thread002.test thread003.test thread004.test trans2.test vacuum3.test incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test | > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | speed4p.test sqllimits1.test tkt2686.test thread001.test thread002.test thread003.test thread004.test thread005.test trans2.test vacuum3.test incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test |
︙ | ︙ |
Changes to test/thread003.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests that attempt to break the pcache module # by bombarding it with simultaneous requests from multiple threads. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests that attempt to break the pcache module # by bombarding it with simultaneous requests from multiple threads. # # $Id: thread003.test,v 1.7 2009/03/12 14:43:28 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/thread_common.tcl if {[info commands sqlthread] eq ""} { finish_test |
︙ | ︙ | |||
154 155 156 157 158 159 160 | } {0} # In this test case, one thread is continually querying the database. # The other thread does not have a database connection, but calls # sqlite3_release_memory() over and over again. # set nSecond 30 | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | } {0} # In this test case, one thread is continually querying the database. # The other thread does not have a database connection, but calls # sqlite3_release_memory() over and over again. # set nSecond 30 puts "Starting thread003.4 (should run for ~$nSecond seconds)" unset -nocomplain finished(1) unset -nocomplain finished(2) do_test thread003.4 { thread_spawn finished(1) $thread_procs [format { set iEnd [expr {[clock_seconds] + %d}] set ::DB [sqlthread open test.db] |
︙ | ︙ |
Added test/thread005.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 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 |