From: danielk1977 Date: Mon, 26 Mar 2007 10:27:18 +0000 (+0000) Subject: Add some tests and fixes surrounding exclusive-access mode and the pager change-count... X-Git-Tag: version-3.6.10~2454 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ded6f4b2fef47dea09f167b8a5dea7a381e6fabc;p=thirdparty%2Fsqlite.git Add some tests and fixes surrounding exclusive-access mode and the pager change-counter. (CVS 3716) FossilOrigin-Name: 72cb2e1a73cd09d32900bb473377f66ff55058fb --- diff --git a/manifest b/manifest index 792649f6ff..25630ba70d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssome\sdocumentation\sfor\spragma\slocking_mode.\s(CVS\s3715) -D 2007-03-26T08:41:13 +C Add\ssome\stests\sand\sfixes\ssurrounding\sexclusive-access\smode\sand\sthe\spager\schange-counter.\s(CVS\s3716) +D 2007-03-26T10:27:19 F Makefile.in 1fe3d0b46e40fd684e1e61f8e8056cefed16de9f F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -86,7 +86,7 @@ F src/os_unix.c 4642f23ed0c1ae0f1440db1d2b4231348af69360 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c 1d1d0989b0f235751504292c2f28e81044be0d70 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 5846d0c1b010145b656719c7579018f906f2663f +F src/pager.c 4c83ffbb02386d0fd90eef51c16097c74e5b785a F src/pager.h 3c16500c25051536e43fb19e246e58fc7cb51d9f F src/parse.y bcfe366c1fd61cfc40e5344eb69a31997a821af0 F src/pragma.c 9cb8b94e7d38ba35a86037bd517d07ba9870b4b2 @@ -199,7 +199,8 @@ F test/distinctagg.test 2b89d1c5220d966a30ba4b40430338669301188b F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52 F test/enc2.test 45710bacfa9df29720bc84c067dfdf8c8ddfb797 F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030 -F test/exclusive.test c2d8b75882a3f35057209e6d5e99737a1ef33d80 +F test/exclusive.test 83871f52ab1015dc1bfbf86b96e2ece29094d129 +F test/exclusive2.test 187993598a83257f4a1126a40d89144c01965500 F test/expr.test c78843f730ccbe973d0c2ad1c99978f936893131 F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce F test/format4.test bf3bed3b13c63abfb3cfec232597a319a31d0bcc @@ -438,7 +439,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 899e60707bea0fabab2ff3ac8a3fbb676a539120 -R c95c47b55de39c81a885f5c3b87d8ccb +P 394b174e59262a84c530ea73c367d8c389a681b5 +R b9cfbb38bcb177f91ab61bb6f0720497 U danielk1977 -Z a34ef51e67b415410cd73312e1288145 +Z bbf2e9e72a548a49626e962c15cb3299 diff --git a/manifest.uuid b/manifest.uuid index 69c2948012..cd9a0bed80 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -394b174e59262a84c530ea73c367d8c389a681b5 \ No newline at end of file +72cb2e1a73cd09d32900bb473377f66ff55058fb \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 41528a8b46..a078f7fe49 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.295 2007/03/26 08:05:12 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.296 2007/03/26 10:27:19 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -927,7 +927,7 @@ static int pager_unwritelock(Pager *pPager){ } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen && !pPager->exclusiveMode ){ - if( pPager->exclusiveMode ){ + if( !pPager->exclusiveMode ){ sqlite3OsClose(&pPager->stfd); pPager->stmtOpen = 0; }else{ @@ -3897,23 +3897,25 @@ static int pager_incr_changecounter(Pager *pPager){ u32 change_counter; int rc; - /* Open page 1 of the file for writing. */ - rc = sqlite3PagerGet(pPager, 1, &pPgHdr); - if( rc!=SQLITE_OK ) return rc; - rc = sqlite3PagerWrite(pPgHdr); - if( rc!=SQLITE_OK ) return rc; - - /* Read the current value at byte 24. */ - change_counter = retrieve32bits(pPgHdr, 24); - - /* Increment the value just read and write it back to byte 24. */ - change_counter++; - put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); - pPager->iChangeCount = change_counter; - - /* Release the page reference. */ - sqlite3PagerUnref(pPgHdr); - pPager->changeCountDone = 1; + if( !pPager->changeCountDone ){ + /* Open page 1 of the file for writing. */ + rc = sqlite3PagerGet(pPager, 1, &pPgHdr); + if( rc!=SQLITE_OK ) return rc; + rc = sqlite3PagerWrite(pPgHdr); + if( rc!=SQLITE_OK ) return rc; + + /* Read the current value at byte 24. */ + change_counter = retrieve32bits(pPgHdr, 24); + + /* Increment the value just read and write it back to byte 24. */ + change_counter++; + put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); + pPager->iChangeCount = change_counter; + + /* Release the page reference. */ + sqlite3PagerUnref(pPgHdr); + pPager->changeCountDone = 1; + } return SQLITE_OK; } diff --git a/test/exclusive.test b/test/exclusive.test index 56019805bf..aff4e8313d 100644 --- a/test/exclusive.test +++ b/test/exclusive.test @@ -8,9 +8,11 @@ # May you share freely, never taking more than you give. # #*********************************************************************** -# This file implements regression tests for SQLite library. +# This file implements regression tests for SQLite library. The focus +# of these tests is exclusive access mode (i.e. the thing activated by +# "PRAGMA locking_mode = EXCLUSIVE"). # -# $Id: exclusive.test,v 1.2 2007/03/26 08:05:12 danielk1977 Exp $ +# $Id: exclusive.test,v 1.3 2007/03/26 10:27:19 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl diff --git a/test/exclusive2.test b/test/exclusive2.test new file mode 100644 index 0000000000..ee8cd66009 --- /dev/null +++ b/test/exclusive2.test @@ -0,0 +1,242 @@ +# 2007 March 24 +# +# 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# $Id: exclusive2.test,v 1.1 2007/03/26 10:27:19 danielk1977 Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!pager_pragmas} { + finish_test + return +} + +proc pagerChangeCounter {filename {new ""}} { + set fd [open $filename a+] + fconfigure $fd -translation binary -encoding binary + if {$new ne ""} { + seek $fd 24 + set a [expr {($new&0xFF000000)>>24}] + set b [expr {($new&0x00FF0000)>>16}] + set c [expr {($new&0x0000FF00)>>8}] + set d [expr {($new&0x000000FF)}] + puts $fd [binary format cccc $a $b $c $d] + } + + seek $fd 24 + foreach {a b c d} [list 0 0 0 0] {} + binary scan [read $fd 4] cccc a b c d + set ret [expr ($a&0x000000FF)<<24] + incr ret [expr ($b&0x000000FF)<<16] + incr ret [expr ($c&0x000000FF)<<8] + incr ret [expr ($d&0x000000FF)<<0] + + close $fd + return $ret +} + +proc t1sig {{db db}} { + execsql {SELECT count(*), md5sum(a) FROM t1} $db +} +do_test exclusive2-1.0 { + pagerChangeCounter test.db +} {0} + +#----------------------------------------------------------------------- +# The following tests - exclusive2-1.X - check that: +# +# 1-3: Build a database with connection 1, calculate a signature. +# 4-9: Modify the database using a second connection, then reset +# the pager change-counter to the value it had before the modifications. +# 8: Check that using the first connection, the database signature +# is still the same. This is because it uses the in-memory cache. +# It can't tell the db has changed because we reset the change-counter. +# 9: Increment the change-counter. +# 10: Ensure that the first connection now sees the updated database. It +# sees the change-counter has been incremented and discards the +# invalid in-memory cache. +# +do_test exclusive2-1.1 { + execsql { + BEGIN; + CREATE TABLE t1(a UNIQUE); + INSERT INTO t1 VALUES(randstr(10, 400)); + INSERT INTO t1 VALUES(randstr(10, 400)); + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + COMMIT; + SELECT count(*) FROM t1; + } +} {64} +do_test exclusive2-1.2 { + set ::sig [t1sig] + pagerChangeCounter test.db +} {1} +do_test exclusive2-1.3 { + t1sig +} $::sig +do_test exclusive2-1.4 { + sqlite3 db2 test.db + t1sig db2 +} $::sig +do_test exclusive2-1.5 { + execsql { + DELETE FROM t1; + } db2 + expr {[t1sig db2] eq $::sig} +} 0 +do_test exclusive2-1.6 { + pagerChangeCounter test.db +} {2} +do_test exclusive2-1.7 { + pagerChangeCounter test.db 1 +} {1} +do_test exclusive2-1.9 { + t1sig + expr {[t1sig] eq $::sig} +} {1} +do_test exclusive2-1.10 { + pagerChangeCounter test.db 2 +} {2} +do_test exclusive2-1.11 { + expr {[t1sig] eq $::sig} +} {0} + +#-------------------------------------------------------------------- +# These tests - exclusive2-2.X - are similar to exclusive2-1.X, +# except that they are run with locking_mode=EXCLUSIVE. +# +# 1-3: Build a database with exclusive-access connection 1, +# calculate a signature. +# 4: Corrupt the database by writing 10000 bytes of garbage +# starting at the beginning of page 2. Check that connection 1 +# still works. It should be accessing the in-memory cache. +# 5-6: Modify the dataase change-counter. Connection 1 still works +# entirely from in-memory cache, because it doesn't check the +# change-counter. +# 7-8 Set the locking-mode back to normal. After the db is unlocked, +# SQLite detects the modified change-counter and discards the +# in-memory cache. Then it finds the corruption caused in step 4.... +# +do_test exclusive2-2.1 { + execsql {PRAGMA locking_mode = exclusive;} + execsql { + BEGIN; + INSERT INTO t1 VALUES(randstr(10, 400)); + INSERT INTO t1 VALUES(randstr(10, 400)); + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + INSERT INTO t1 SELECT randstr(10, 400) FROM t1; + COMMIT; + SELECT count(*) FROM t1; + } +} {64} +do_test exclusive2-2.2 { + set ::sig [t1sig] + pagerChangeCounter test.db +} {3} +do_test exclusive2-2.3 { + t1sig +} $::sig + +do_test exclusive2-2.4 { + set fd [open test.db a] + seek $fd 1024 + puts -nonewline $fd [string repeat [binary format c 0] 10000] + t1sig +} $::sig + +do_test exclusive2-2.5 { + pagerChangeCounter test.db 5 +} {5} +do_test exclusive2-2.6 { + t1sig +} $::sig +do_test exclusive2-2.7 { + execsql {PRAGMA locking_mode = normal} + t1sig +} $::sig + +do_test exclusive2-2.8 { + set rc [catch {t1sig} msg] + list $rc $msg +} {1 {database disk image is malformed}} + +#-------------------------------------------------------------------- +# These tests - exclusive2-3.X - verify that the pager change-counter +# is only incremented by the first change when in exclusive access +# mode. In normal mode, the change-counter is incremented once +# per write-transaction. +# + +db close +db2 close +file delete -force test.db +file delete -force test.db-journal + +do_test exclusive2-3.0 { + sqlite3 db test.db + execsql { + BEGIN; + CREATE TABLE t1(a UNIQUE); + INSERT INTO t1 VALUES(randstr(10, 400)); + INSERT INTO t1 VALUES(randstr(10, 400)); + COMMIT; + } + pagerChangeCounter test.db +} {1} +do_test exclusive2-3.1 { + execsql { + INSERT INTO t1 VALUES(randstr(10, 400)); + } + pagerChangeCounter test.db +} {2} +do_test exclusive2-3.2 { + execsql { + INSERT INTO t1 VALUES(randstr(10, 400)); + } + pagerChangeCounter test.db +} {3} +do_test exclusive2-3.3 { + execsql { + PRAGMA locking_mode = exclusive; + INSERT INTO t1 VALUES(randstr(10, 400)); + } + pagerChangeCounter test.db +} {4} +do_test exclusive2-3.4 { + execsql { + INSERT INTO t1 VALUES(randstr(10, 400)); + } + pagerChangeCounter test.db +} {4} +do_test exclusive2-3.5 { + execsql { + PRAGMA locking_mode = normal; + INSERT INTO t1 VALUES(randstr(10, 400)); + } + pagerChangeCounter test.db +} {4} +do_test exclusive2-3.6 { + execsql { + INSERT INTO t1 VALUES(randstr(10, 400)); + } + pagerChangeCounter test.db +} {5} + +finish_test +