AryaWu/sqlite
0
1# 2007 March 242#3# The author disclaims copyright to this source code. In place of4# a legal notice, here is a blessing:5#6# May you do good and not evil.7# May you find forgiveness for yourself and forgive others.8# May you share freely, never taking more than you give.9#10#***********************************************************************11# This file implements regression tests for SQLite library.12#13# $Id: exclusive2.test,v 1.10 2008/11/27 02:22:11 drh Exp $14 15set testdir [file dirname $argv0]16source $testdir/tester.tcl17 18# Do not use a codec for tests in this file, as the database file is19# manipulated directly using tcl scripts (using the [hexio_write] command).20#21do_not_use_codec22 23ifcapable {!pager_pragmas} {24 finish_test25 return26}27 28# Tests in this file verify that locking_mode=exclusive causes SQLite to29# use cached pages even if the database is changed on disk. This doesn't30# work with mmap.31if {[permutation]=="mmap"} {32 finish_test33 return34}35 36# This module does not work right if the cache spills at unexpected37# moments. So disable the soft-heap-limit.38#39sqlite3_soft_heap_limit 040 41proc pagerChangeCounter {filename new {fd ""}} {42 if {$fd==""} {43 set fd [open $filename RDWR]44 fconfigure $fd -translation binary45 set needClose 146 } else {47 set needClose 048 }49 if {$new ne ""} {50 seek $fd 2451 set a [expr {($new&0xFF000000)>>24}]52 set b [expr {($new&0x00FF0000)>>16}]53 set c [expr {($new&0x0000FF00)>>8}]54 set d [expr {($new&0x000000FF)}]55 puts -nonewline $fd [binary format cccc $a $b $c $d]56 flush $fd57 }58 59 seek $fd 2460 foreach {a b c d} [list 0 0 0 0] {}61 binary scan [read $fd 4] cccc a b c d62 set ret [expr ($a&0x000000FF)<<24]63 incr ret [expr ($b&0x000000FF)<<16]64 incr ret [expr ($c&0x000000FF)<<8]65 incr ret [expr ($d&0x000000FF)<<0]66 67 if {$needClose} {close $fd}68 return $ret69}70 71proc readPagerChangeCounter {filename} {72 set fd [open $filename RDONLY]73 fconfigure $fd -translation binary74 75 seek $fd 2476 foreach {a b c d} [list 0 0 0 0] {}77 binary scan [read $fd 4] cccc a b c d78 set ret [expr ($a&0x000000FF)<<24]79 incr ret [expr ($b&0x000000FF)<<16]80 incr ret [expr ($c&0x000000FF)<<8]81 incr ret [expr ($d&0x000000FF)<<0]82 83 close $fd84 return $ret85}86 87 88proc t1sig {{db db}} {89 execsql {SELECT count(*), md5sum(a) FROM t1} $db90}91do_test exclusive2-1.0 {92 readPagerChangeCounter test.db93} {0}94 95#-----------------------------------------------------------------------96# The following tests - exclusive2-1.X - check that:97#98# 1-3: Build a database with connection 1, calculate a signature.99# 4-7: Modify the database using a second connection in a way that100# does not modify the freelist, then reset the pager change-counter101# to the value it had before the modifications.102# 8: Check that using the first connection, the database signature103# is still the same. This is because it uses the in-memory cache.104# It can't tell the db has changed because we reset the change-counter.105# 9: Increment the change-counter.106# 10: Ensure that the first connection now sees the updated database. It107# sees the change-counter has been incremented and discards the 108# invalid in-memory cache.109#110# This will only work if the database cache is large enough to hold 111# the entire database. In the case of 1024 byte pages, this means112# the cache size must be at least 17. Otherwise, some pages will be113# loaded from the database file in step 8.114#115# For similar reasons, this test does not work with the memsubsys1 permutation.116# Permutation memsubsys1 configures the pcache subsystem to use a static117# allocation of 24 pages (shared between all pagers). This is not enough for118# this test.119#120do_test exclusive2-1.1 {121 execsql {122 BEGIN;123 CREATE TABLE t1(a, b);124 INSERT INTO t1(a, b) VALUES(randstr(10, 400), 0);125 INSERT INTO t1(a, b) VALUES(randstr(10, 400), 0);126 INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;127 INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;128 INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;129 INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;130 INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;131 COMMIT;132 SELECT count(*) FROM t1;133 }134} {64}135do_test exclusive2-1.2.1 {136 # Make sure the pager cache is large enough to store the 137 # entire database.138 set nPage [expr [file size test.db]/1024]139 if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {140 execsql "PRAGMA cache_size = $nPage"141 }142 expr {[execsql {PRAGMA cache_size}] >= $nPage}143} {1}144do_test exclusive2-1.2 {145 set ::sig [t1sig]146 readPagerChangeCounter test.db147} {1}148do_test exclusive2-1.3 {149 t1sig150} $::sig151do_test exclusive2-1.4 {152 sqlite3 db2 test.db153 t1sig db2154} $::sig155do_test exclusive2-1.5 {156 execsql {157 UPDATE t1 SET b=a, a=0;158 } db2159 expr {[t1sig db2] eq $::sig}160} 0161do_test exclusive2-1.6 {162 readPagerChangeCounter test.db163} {2}164do_test exclusive2-1.7 {165 pagerChangeCounter test.db 1166} {1}167if {[permutation] != "memsubsys1"} {168 do_test exclusive2-1.9 {169 t1sig170 expr {[t1sig] eq $::sig}171 } {1}172}173do_test exclusive2-1.10 {174 pagerChangeCounter test.db 2175} {2}176do_test exclusive2-1.11 {177 expr {[t1sig] eq $::sig}178} {0}179db2 close180 181#--------------------------------------------------------------------182# These tests - exclusive2-2.X - are similar to exclusive2-1.X, 183# except that they are run with locking_mode=EXCLUSIVE.184#185# 1-3: Build a database with exclusive-access connection 1, 186# calculate a signature.187# 4: Corrupt the database by writing 10000 bytes of garbage188# starting at the beginning of page 2. Check that connection 1189# still works. It should be accessing the in-memory cache.190# 5-6: Modify the dataase change-counter. Connection 1 still works191# entirely from in-memory cache, because it doesn't check the192# change-counter.193# 7-8 Set the locking-mode back to normal. After the db is unlocked,194# SQLite detects the modified change-counter and discards the195# in-memory cache. Then it finds the corruption caused in step 4....196#197# As above, this test is only applicable if the pager cache is198# large enough to hold the entire database. With 1024 byte pages,199# this means 19 pages. We also need to disable the soft-heap-limit200# to prevent memory-induced cache spills.201#202do_test exclusive2-2.1 {203 execsql {PRAGMA cache_size=1000;}204 execsql {PRAGMA locking_mode = exclusive;}205 execsql {206 BEGIN;207 DELETE FROM t1;208 INSERT INTO t1(a) VALUES(randstr(10, 400));209 INSERT INTO t1(a) VALUES(randstr(10, 400));210 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;211 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;212 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;213 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;214 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;215 COMMIT;216 SELECT count(*) FROM t1;217 }218} {64}219do_test exclusive2-2.2.1 {220 # Make sure the pager cache is large enough to store the 221 # entire database.222 set nPage [expr [file size test.db]/1024]223 if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {224 execsql "PRAGMA cache_size = $nPage"225 }226 expr {[execsql {PRAGMA cache_size}] >= $nPage}227} {1}228do_test exclusive2-2.2 {229 set ::sig [t1sig]230 readPagerChangeCounter test.db231} {3}232do_test exclusive2-2.3 {233 t1sig234} $::sig235 236do_test exclusive2-2.4 {237 set ::fd [open test.db RDWR]238 fconfigure $::fd -translation binary239 seek $::fd 1024240 puts -nonewline $::fd [string repeat [binary format c 0] 10000]241 flush $::fd242 t1sig243} $::sig244 245do_test exclusive2-2.5 {246 pagerChangeCounter test.db 5 $::fd247} {5}248do_test exclusive2-2.6 {249 t1sig250} $::sig251do_test exclusive2-2.7 {252 execsql {PRAGMA locking_mode = normal}253 t1sig254} $::sig255 256do_test exclusive2-2.8 {257 set rc [catch {t1sig} msg]258 list $rc $msg259} {1 {database disk image is malformed}}260 261#--------------------------------------------------------------------262# These tests - exclusive2-3.X - verify that the pager change-counter263# is only incremented by the first change when in exclusive access264# mode. In normal mode, the change-counter is incremented once265# per write-transaction.266#267 268db close269catch {close $::fd}270forcedelete test.db271forcedelete test.db-journal272 273do_test exclusive2-3.0 {274 sqlite3 db test.db275 execsql {276 BEGIN;277 CREATE TABLE t1(a UNIQUE);278 INSERT INTO t1 VALUES(randstr(200, 200));279 INSERT INTO t1 VALUES(randstr(200, 200));280 COMMIT;281 }282 readPagerChangeCounter test.db283} {1}284do_test exclusive2-3.1 {285 execsql {286 INSERT INTO t1 VALUES(randstr(200, 200));287 }288 readPagerChangeCounter test.db289} {2}290do_test exclusive2-3.2 {291 execsql {292 INSERT INTO t1 VALUES(randstr(200, 200));293 }294 readPagerChangeCounter test.db295} {3}296do_test exclusive2-3.3 {297 execsql {298 PRAGMA locking_mode = exclusive;299 INSERT INTO t1 VALUES(randstr(200, 200));300 }301 readPagerChangeCounter test.db302} {4}303do_test exclusive2-3.4 {304 execsql {305 INSERT INTO t1 VALUES(randstr(200, 200));306 }307 readPagerChangeCounter test.db308} {4}309do_test exclusive2-3.5 {310 execsql {311 PRAGMA locking_mode = normal;312 INSERT INTO t1 VALUES(randstr(200, 200));313 }314 readPagerChangeCounter test.db315} {4}316do_test exclusive2-3.6 {317 execsql {318 INSERT INTO t1 VALUES(randstr(200, 200));319 }320 readPagerChangeCounter test.db321} {5}322sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)323 324finish_test325 