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 |