OLD | NEW |
(Empty) | |
| 1 # 2011 August 08 |
| 2 # |
| 3 # The author disclaims copyright to this source code. In place of |
| 4 # 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 |
| 13 set testdir [file dirname $argv0] |
| 14 source $testdir/tester.tcl |
| 15 source $testdir/lock_common.tcl |
| 16 source $testdir/malloc_common.tcl |
| 17 |
| 18 ifcapable !mergesort { |
| 19 finish_test |
| 20 return |
| 21 } |
| 22 |
| 23 set testprefix indexfault |
| 24 |
| 25 # Set up the custom fault-injector. This is further configured by using |
| 26 # different values for $::custom_filter and different implementations |
| 27 # of Tcl proc [xCustom] for each test case. |
| 28 # |
| 29 proc 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 true |
| 39 shmfault filter $::custom_filter |
| 40 shmfault script xCustom |
| 41 } |
| 42 proc custom_injectuninstall {} { |
| 43 catch {db close} |
| 44 catch {db2 close} |
| 45 shmfault delete |
| 46 } |
| 47 set ::custom_ifail -1 |
| 48 set ::custom_nfail -1 |
| 49 proc custom_injectstart {iFail} { |
| 50 set ::custom_ifail $iFail |
| 51 set ::custom_nfail 0 |
| 52 } |
| 53 proc custom_injectstop {} { |
| 54 set ::custom_ifail -1 |
| 55 return $::custom_nfail |
| 56 } |
| 57 } |
| 58 proc uninstall_custom_faultsim {} { |
| 59 unset -nocomplain ::FAULTSIM(custom) |
| 60 } |
| 61 |
| 62 |
| 63 #------------------------------------------------------------------------- |
| 64 # These tests - indexfault-1.* - Build an index on a smallish table with |
| 65 # all different kinds of fault-injection. The CREATE INDEX is run once |
| 66 # with default options and once with a 50KB soft-heap-limit. |
| 67 # |
| 68 do_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; -- 2 |
| 73 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 4 |
| 74 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 8 |
| 75 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 16 |
| 76 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 32 |
| 77 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 64 |
| 78 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 128 |
| 79 INSERT INTO t1 SELECT randomblob(202) FROM t1; -- 256 |
| 80 COMMIT; |
| 81 } |
| 82 faultsim_save_and_close |
| 83 |
| 84 do_faultsim_test 1.1 -prep { |
| 85 faultsim_restore_and_reopen |
| 86 } -body { |
| 87 execsql { CREATE INDEX i1 ON t1(x) } |
| 88 faultsim_test_result {0 {}} |
| 89 faultsim_integrity_check |
| 90 } |
| 91 ifcapable memorymanage { |
| 92 set soft_limit [sqlite3_soft_heap_limit 50000] |
| 93 do_faultsim_test 2.1 -prep { |
| 94 faultsim_restore_and_reopen |
| 95 } -body { |
| 96 execsql { CREATE INDEX i1 ON t1(x) } |
| 97 faultsim_test_result {0 {}} |
| 98 } |
| 99 sqlite3_soft_heap_limit $soft_limit |
| 100 } |
| 101 |
| 102 #------------------------------------------------------------------------- |
| 103 # These are similar to the indexfault-1.* tests, except they create an |
| 104 # index with more than one column. |
| 105 # |
| 106 sqlite3 db test.db |
| 107 do_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; -- 2 |
| 118 INSERT INTO t1 SELECT |
| 119 randomblob(30), randomblob(30), randomblob(30), randomblob(30), |
| 120 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 4 |
| 121 INSERT INTO t1 SELECT |
| 122 randomblob(30), randomblob(30), randomblob(30), randomblob(30), |
| 123 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 8 |
| 124 INSERT INTO t1 SELECT |
| 125 randomblob(30), randomblob(30), randomblob(30), randomblob(30), |
| 126 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 16 |
| 127 INSERT INTO t1 SELECT |
| 128 randomblob(30), randomblob(30), randomblob(30), randomblob(30), |
| 129 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 32 |
| 130 INSERT INTO t1 SELECT |
| 131 randomblob(30), randomblob(30), randomblob(30), randomblob(30), |
| 132 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 64 |
| 133 INSERT INTO t1 SELECT |
| 134 randomblob(30), randomblob(30), randomblob(30), randomblob(30), |
| 135 randomblob(30), randomblob(30), randomblob(30) FROM t1; -- 128 |
| 136 COMMIT; |
| 137 } |
| 138 faultsim_save_and_close |
| 139 |
| 140 do_faultsim_test 2.1 -prep { |
| 141 faultsim_restore_and_reopen |
| 142 } -body { |
| 143 execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) } |
| 144 faultsim_test_result {0 {}} |
| 145 faultsim_integrity_check |
| 146 } |
| 147 ifcapable memorymanage { |
| 148 set soft_limit [sqlite3_soft_heap_limit 50000] |
| 149 do_faultsim_test 2.2 -prep { |
| 150 faultsim_restore_and_reopen |
| 151 } -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_limit |
| 156 } |
| 157 |
| 158 #------------------------------------------------------------------------- |
| 159 # The following tests - indexfault-2.* - all attempt to build a index |
| 160 # on table t1 in the main database with injected IO errors. Individual |
| 161 # 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 the |
| 167 # 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 database |
| 171 # file (and written into the temporary b-tree), sqlite3_release_memory() |
| 172 # is called to free as much memory as possible. This causes the temp |
| 173 # 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 extra |
| 175 # opportunities for IO errors. |
| 176 # |
| 177 install_custom_faultsim |
| 178 |
| 179 # Set up a table to build indexes on. Save the setup using the |
| 180 # [faultsim_save_and_close] mechanism. |
| 181 # |
| 182 sqlite3 db test.db |
| 183 do_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; -- 2 |
| 189 INSERT INTO t1 SELECT randomblob(11002) FROM t1; -- 4 |
| 190 INSERT INTO t1 SELECT randomblob(11003) FROM t1; -- 8 |
| 191 INSERT INTO t1 SELECT randomblob(11004) FROM t1; -- 16 |
| 192 INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 32 |
| 193 INSERT INTO t1 SELECT randomblob(11006) FROM t1; -- 64 |
| 194 INSERT INTO t1 SELECT randomblob(11007) FROM t1; -- 128 |
| 195 INSERT INTO t1 SELECT randomblob(11008) FROM t1; -- 256 |
| 196 INSERT INTO t1 SELECT randomblob(11009) FROM t1; -- 512 |
| 197 COMMIT; |
| 198 } |
| 199 faultsim_save_and_close |
| 200 |
| 201 set ::custom_filter xOpen |
| 202 proc xCustom {args} { |
| 203 incr ::custom_ifail -1 |
| 204 if {$::custom_ifail==0} { |
| 205 incr ::custom_nfail |
| 206 return "SQLITE_IOERR" |
| 207 } |
| 208 return "SQLITE_OK" |
| 209 } |
| 210 do_faultsim_test 3.1 -faults custom -prep { |
| 211 faultsim_restore_and_reopen |
| 212 } -body { |
| 213 execsql { CREATE INDEX i1 ON t1(x) } |
| 214 faultsim_test_result {0 {}} |
| 215 } |
| 216 ifcapable memorymanage { |
| 217 set soft_limit [sqlite3_soft_heap_limit 50000] |
| 218 do_faultsim_test 3.2 -faults custom -prep { |
| 219 faultsim_restore_and_reopen |
| 220 } -body { |
| 221 execsql { CREATE INDEX i1 ON t1(x) } |
| 222 faultsim_test_result {0 {}} |
| 223 } |
| 224 sqlite3_soft_heap_limit $soft_limit |
| 225 } |
| 226 |
| 227 set ::custom_filter {xOpen xWrite} |
| 228 proc xCustom {method args} { |
| 229 if {$method == "xOpen"} { |
| 230 if {[lindex $args 0] == ""} { |
| 231 incr ::nTmpOpen 1 |
| 232 if {$::nTmpOpen == 3} { return "failme" } |
| 233 } |
| 234 return "SQLITE_OK" |
| 235 } |
| 236 if {$::custom_ifail<200 && [lindex $args 1] == "failme"} { |
| 237 incr ::custom_ifail -1 |
| 238 if {$::custom_ifail==0} { |
| 239 incr ::custom_nfail |
| 240 return "SQLITE_IOERR" |
| 241 } |
| 242 } |
| 243 return "SQLITE_OK" |
| 244 } |
| 245 |
| 246 do_faultsim_test 3.3 -faults custom -prep { |
| 247 faultsim_restore_and_reopen |
| 248 set ::nTmpOpen 0 |
| 249 } -body { |
| 250 execsql { CREATE INDEX i1 ON t1(x) } |
| 251 faultsim_test_result {0 {}} |
| 252 } |
| 253 |
| 254 ifcapable memorymanage { |
| 255 set soft_limit [sqlite3_soft_heap_limit 50000] |
| 256 do_faultsim_test 3.4 -faults custom -prep { |
| 257 faultsim_restore_and_reopen |
| 258 set ::nTmpOpen 0 |
| 259 } -body { |
| 260 execsql { CREATE INDEX i1 ON t1(x) } |
| 261 faultsim_test_result {0 {}} |
| 262 } |
| 263 sqlite3_soft_heap_limit $soft_limit |
| 264 } |
| 265 |
| 266 uninstall_custom_faultsim |
| 267 |
| 268 #------------------------------------------------------------------------- |
| 269 # Test 4: After a certain amount of data has been read from the main database |
| 270 # file (and written into the temporary b-tree), sqlite3_release_memory() is |
| 271 # called to free as much memory as possible. This causes the temp b-tree to be |
| 272 # flushed to disk. So that before its contents can be transfered to a PMA they |
| 273 # must be read back from disk - creating extra opportunities for IO errors. |
| 274 # |
| 275 install_custom_faultsim |
| 276 |
| 277 catch { db close } |
| 278 forcedelete test.db |
| 279 sqlite3 db test.db |
| 280 |
| 281 do_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; -- 2 |
| 287 INSERT INTO t1 SELECT randomblob(11002) FROM t1; -- 4 |
| 288 INSERT INTO t1 SELECT randomblob(11003) FROM t1; -- 8 |
| 289 INSERT INTO t1 SELECT randomblob(11004) FROM t1; -- 16 |
| 290 INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 32 |
| 291 INSERT INTO t1 SELECT randomblob(11005) FROM t1; -- 64 |
| 292 COMMIT; |
| 293 } |
| 294 faultsim_save_and_close |
| 295 |
| 296 testvfs tvfs |
| 297 tvfs script xRead |
| 298 tvfs filter xRead |
| 299 set ::nRead 0 |
| 300 proc xRead {method file args} { |
| 301 if {[file tail $file] == "test.db"} { incr ::nRead } |
| 302 } |
| 303 |
| 304 do_test 4.1 { |
| 305 sqlite3 db test.db -vfs tvfs |
| 306 execsql { CREATE INDEX i1 ON t1(x) } |
| 307 } {} |
| 308 |
| 309 db close |
| 310 tvfs delete |
| 311 |
| 312 set ::custom_filter xRead |
| 313 proc xCustom {method file args} { |
| 314 incr ::nReadCall |
| 315 if {$::nReadCall >= ($::nRead/5)} { |
| 316 if {$::nReadCall == ($::nRead/5)} { |
| 317 set nByte [sqlite3_release_memory [expr 64*1024*1024]] |
| 318 sqlite3_soft_heap_limit 20000 |
| 319 } |
| 320 if {$file == ""} { |
| 321 incr ::custom_ifail -1 |
| 322 if {$::custom_ifail==0} { |
| 323 incr ::custom_nfail |
| 324 return "SQLITE_IOERR" |
| 325 } |
| 326 } |
| 327 } |
| 328 return "SQLITE_OK" |
| 329 } |
| 330 |
| 331 do_faultsim_test 4.2 -faults custom -prep { |
| 332 faultsim_restore_and_reopen |
| 333 set ::nReadCall 0 |
| 334 sqlite3_soft_heap_limit 0 |
| 335 } -body { |
| 336 execsql { CREATE INDEX i1 ON t1(x) } |
| 337 faultsim_test_result {0 {}} |
| 338 } |
| 339 |
| 340 uninstall_custom_faultsim |
| 341 |
| 342 finish_test |
OLD | NEW |