AryaWu/sqlite
0
1# 2011 August 082#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#12 13set testdir [file dirname $argv0]14source $testdir/tester.tcl15source $testdir/lock_common.tcl16source $testdir/malloc_common.tcl17 18ifcapable !mergesort {19 finish_test20 return21}22 23set testprefix indexfault24 25# Set up the custom fault-injector. This is further configured by using26# different values for $::custom_filter and different implementations27# of Tcl proc [xCustom] for each test case.28#29proc install_custom_faultsim {} {30 set ::FAULTSIM(custom) [list \31 -injectinstall custom_injectinstall \32 -injectstart custom_injectstart \33 -injectstop custom_injectstop \34 -injecterrlist {{1 {disk I/O error}}} \35 -injectuninstall custom_injectuninstall \36 ]37 proc custom_injectinstall {} {38 testvfs shmfault -default true39 shmfault filter $::custom_filter40 shmfault script xCustom41 }42 proc custom_injectuninstall {} {43 catch {db close}44 catch {db2 close}45 shmfault delete46 }47 set ::custom_ifail -148 set ::custom_nfail -149 proc custom_injectstart {iFail} {50 set ::custom_ifail $iFail51 set ::custom_nfail 052 }53 proc custom_injectstop {} {54 set ::custom_ifail -155 return $::custom_nfail56 }57}58proc uninstall_custom_faultsim {} {59 unset -nocomplain ::FAULTSIM(custom)60}61 62 63#-------------------------------------------------------------------------64# These tests - indexfault-1.* - Build an index on a smallish table with65# all different kinds of fault-injection. The CREATE INDEX is run once66# with default options and once with a 50KB soft-heap-limit.67#68do_execsql_test 1.0 {69 BEGIN;70 CREATE TABLE t1(x);71 INSERT INTO t1 VALUES(randomblob(202));72 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 273 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 474 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 875 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 1676 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 3277 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 6478 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 12879 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 25680 COMMIT;81}82faultsim_save_and_close83 84do_faultsim_test 1.1 -prep {85 faultsim_restore_and_reopen86} -body {87 execsql { CREATE INDEX i1 ON t1(x) }88 faultsim_test_result {0 {}} 89 faultsim_integrity_check90}91ifcapable memorymanage {92 set soft_limit [sqlite3_soft_heap_limit 50000]93 do_faultsim_test 2.1 -prep {94 faultsim_restore_and_reopen95 } -body {96 execsql { CREATE INDEX i1 ON t1(x) }97 faultsim_test_result {0 {}} 98 }99 sqlite3_soft_heap_limit $soft_limit100}101 102#-------------------------------------------------------------------------103# These are similar to the indexfault-1.* tests, except they create an104# index with more than one column.105#106sqlite3 db test.db107do_execsql_test 2.0 {108 BEGIN;109 DROP TABLE IF EXISTS t1;110 CREATE TABLE t1(t,u,v,w,x,y,z);111 INSERT INTO t1 VALUES(112 randomblob(30), randomblob(30), randomblob(30), randomblob(30),113 randomblob(30), randomblob(30), randomblob(30)114 );115 INSERT INTO t1 SELECT 116 randomblob(30), randomblob(30), randomblob(30), randomblob(30),117 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 2118 INSERT INTO t1 SELECT 119 randomblob(30), randomblob(30), randomblob(30), randomblob(30),120 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 4121 INSERT INTO t1 SELECT 122 randomblob(30), randomblob(30), randomblob(30), randomblob(30),123 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 8124 INSERT INTO t1 SELECT 125 randomblob(30), randomblob(30), randomblob(30), randomblob(30),126 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 16127 INSERT INTO t1 SELECT 128 randomblob(30), randomblob(30), randomblob(30), randomblob(30),129 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 32130 INSERT INTO t1 SELECT 131 randomblob(30), randomblob(30), randomblob(30), randomblob(30),132 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 64133 INSERT INTO t1 SELECT 134 randomblob(30), randomblob(30), randomblob(30), randomblob(30),135 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 128136 COMMIT;137}138faultsim_save_and_close139 140do_faultsim_test 2.1 -prep {141 faultsim_restore_and_reopen142} -body {143 execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) }144 faultsim_test_result {0 {}} 145 faultsim_integrity_check146}147ifcapable memorymanage {148 set soft_limit [sqlite3_soft_heap_limit 50000]149 do_faultsim_test 2.2 -prep {150 faultsim_restore_and_reopen151 } -body {152 execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) }153 faultsim_test_result {0 {}} 154 }155 sqlite3_soft_heap_limit $soft_limit156}157 158#-------------------------------------------------------------------------159# The following tests - indexfault-2.* - all attempt to build a index160# on table t1 in the main database with injected IO errors. Individual161# test cases work as follows:162#163# 3.1: IO errors injected into xOpen() calls.164# 3.2: As 7.1, but with a low (50KB) soft-heap-limit.165#166# 3.3: IO errors injected into the first 200 write() calls made on the167# second temporary file.168# 3.4: As 7.3, but with a low (50KB) soft-heap-limit.169#170# 3.5: After a certain amount of data has been read from the main database171# file (and written into the temporary b-tree), sqlite3_release_memory()172# is called to free as much memory as possible. This causes the temp173# b-tree to be flushed to disk. So that before its contents can be 174# transfered to a PMA they must be read back from disk - creating extra175# opportunities for IO errors.176#177install_custom_faultsim178 179# Set up a table to build indexes on. Save the setup using the 180# [faultsim_save_and_close] mechanism.181# 182sqlite3 db test.db183do_execsql_test 3.0 {184 BEGIN;185 DROP TABLE IF EXISTS t1;186 CREATE TABLE t1(x);187 INSERT INTO t1 VALUES(randomblob(11000));188 INSERT INTO t1 SELECT randomblob(11001) FROM t1; -- 2189 INSERT INTO t1 SELECT randomblob(11002) FROM t1; -- 4190 INSERT INTO t1 SELECT randomblob(11003) FROM t1; -- 8191 INSERT INTO t1 SELECT randomblob(11004) FROM t1; -- 16192 INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 32193 INSERT INTO t1 SELECT randomblob(11006) FROM t1; -- 64194 INSERT INTO t1 SELECT randomblob(11007) FROM t1; -- 128195 INSERT INTO t1 SELECT randomblob(11008) FROM t1; -- 256196 INSERT INTO t1 SELECT randomblob(11009) FROM t1; -- 512197 COMMIT;198}199faultsim_save_and_close200 201set ::custom_filter xOpen202proc xCustom {args} {203 incr ::custom_ifail -1204 if {$::custom_ifail==0} {205 incr ::custom_nfail206 return "SQLITE_IOERR"207 }208 return "SQLITE_OK"209}210do_faultsim_test 3.1 -faults custom -prep {211 faultsim_restore_and_reopen212} -body {213 execsql { CREATE INDEX i1 ON t1(x) }214 faultsim_test_result {0 {}} 215}216ifcapable memorymanage {217 set soft_limit [sqlite3_soft_heap_limit 50000]218 do_faultsim_test 3.2 -faults custom -prep {219 faultsim_restore_and_reopen220 } -body {221 execsql { CREATE INDEX i1 ON t1(x) }222 faultsim_test_result {0 {}} 223 }224 sqlite3_soft_heap_limit $soft_limit225}226 227set ::custom_filter {xOpen xWrite}228proc xCustom {method args} {229 if {$method == "xOpen"} {230 if {[lindex $args 0] == ""} {231 incr ::nTmpOpen 1232 if {$::nTmpOpen == 3} { return "failme" }233 }234 return "SQLITE_OK"235 }236 if {$::custom_ifail<200 && [lindex $args 1] == "failme"} {237 incr ::custom_ifail -1238 if {$::custom_ifail==0} {239 incr ::custom_nfail240 return "SQLITE_IOERR"241 }242 }243 return "SQLITE_OK"244}245 246do_faultsim_test 3.3 -faults custom -prep {247 faultsim_restore_and_reopen248 set ::nTmpOpen 0249} -body {250 execsql { CREATE INDEX i1 ON t1(x) }251 faultsim_test_result {0 {}} 252}253 254ifcapable memorymanage {255 set soft_limit [sqlite3_soft_heap_limit 50000]256 do_faultsim_test 3.4 -faults custom -prep {257 faultsim_restore_and_reopen258 set ::nTmpOpen 0259 } -body {260 execsql { CREATE INDEX i1 ON t1(x) }261 faultsim_test_result {0 {}} 262 }263 sqlite3_soft_heap_limit $soft_limit264}265 266uninstall_custom_faultsim267 268#-------------------------------------------------------------------------269# Test 4: After a certain amount of data has been read from the main database270# file (and written into the temporary b-tree), sqlite3_release_memory() is271# called to free as much memory as possible. This causes the temp b-tree to be272# flushed to disk. So that before its contents can be transfered to a PMA they273# must be read back from disk - creating extra opportunities for IO errors.274# 275install_custom_faultsim276 277catch { db close }278forcedelete test.db279sqlite3 db test.db280 281do_execsql_test 4.0 {282 BEGIN;283 DROP TABLE IF EXISTS t1;284 CREATE TABLE t1(x);285 INSERT INTO t1 VALUES(randomblob(11000));286 INSERT INTO t1 SELECT randomblob(11001) FROM t1; -- 2287 INSERT INTO t1 SELECT randomblob(11002) FROM t1; -- 4288 INSERT INTO t1 SELECT randomblob(11003) FROM t1; -- 8289 INSERT INTO t1 SELECT randomblob(11004) FROM t1; -- 16290 INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 32291 INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 64292 COMMIT;293}294faultsim_save_and_close295 296testvfs tvfs 297tvfs script xRead298tvfs filter xRead299set ::nRead 0300proc xRead {method file args} {301 if {[file tail $file] == "test.db"} { incr ::nRead }302}303 304do_test 4.1 {305 sqlite3 db test.db -vfs tvfs306 execsql { CREATE INDEX i1 ON t1(x) }307} {}308 309db close310tvfs delete311 312set ::custom_filter xRead313proc xCustom {method file args} {314 incr ::nReadCall315 if {$::nReadCall >= ($::nRead/5)} {316 if {$::nReadCall == ($::nRead/5)} {317 set nByte [sqlite3_release_memory [expr 64*1024*1024]]318 sqlite3_soft_heap_limit 20000319 }320 if {$file == ""} {321 incr ::custom_ifail -1322 if {$::custom_ifail==0} {323 incr ::custom_nfail324 return "SQLITE_IOERR"325 }326 }327 }328 return "SQLITE_OK"329}330 331do_faultsim_test 4.2 -faults custom -prep {332 faultsim_restore_and_reopen333 set ::nReadCall 0334 sqlite3_soft_heap_limit 0335} -body {336 execsql { CREATE INDEX i1 ON t1(x) }337 faultsim_test_result {0 {}} 338}339 340do_faultsim_test 5 -prep {341 reset_db342} -body {343 execsql { 344 CREATE TABLE reallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname(a PRIMARY KEY) WITHOUT ROWID;345 }346} -test {347 faultsim_test_result {0 {}} 348}349 350uninstall_custom_faultsim351 352finish_test353 