xref: /sqlite-3.40.0/test/indexfault.test (revision 480c572f)
15279112eSdan# 2011 August 08
25279112eSdan#
35279112eSdan# The author disclaims copyright to this source code.  In place of
45279112eSdan# a legal notice, here is a blessing:
55279112eSdan#
65279112eSdan#    May you do good and not evil.
75279112eSdan#    May you find forgiveness for yourself and forgive others.
85279112eSdan#    May you share freely, never taking more than you give.
95279112eSdan#
105279112eSdan#***********************************************************************
115279112eSdan#
125279112eSdan
135279112eSdanset testdir [file dirname $argv0]
145279112eSdansource $testdir/tester.tcl
155279112eSdansource $testdir/lock_common.tcl
165279112eSdansource $testdir/malloc_common.tcl
175279112eSdan
18689ab897Sdanifcapable !mergesort {
19689ab897Sdan  finish_test
20689ab897Sdan  return
21689ab897Sdan}
22689ab897Sdan
235279112eSdanset testprefix indexfault
245279112eSdan
25262765a7Sdan# Set up the custom fault-injector. This is further configured by using
26262765a7Sdan# different values for $::custom_filter and different implementations
27262765a7Sdan# of Tcl proc [xCustom] for each test case.
28262765a7Sdan#
29262765a7Sdanproc install_custom_faultsim {} {
30262765a7Sdan  set ::FAULTSIM(custom)            [list      \
31262765a7Sdan    -injectinstall   custom_injectinstall    \
32262765a7Sdan    -injectstart     custom_injectstart      \
33262765a7Sdan    -injectstop      custom_injectstop       \
34262765a7Sdan    -injecterrlist   {{1 {disk I/O error}}}  \
35262765a7Sdan    -injectuninstall custom_injectuninstall  \
36262765a7Sdan  ]
37262765a7Sdan  proc custom_injectinstall {} {
38262765a7Sdan    testvfs shmfault -default true
39262765a7Sdan    shmfault filter $::custom_filter
40262765a7Sdan    shmfault script xCustom
41262765a7Sdan  }
42262765a7Sdan  proc custom_injectuninstall {} {
43262765a7Sdan    catch {db  close}
44262765a7Sdan    catch {db2 close}
45262765a7Sdan    shmfault delete
46262765a7Sdan  }
47262765a7Sdan  set ::custom_ifail -1
48262765a7Sdan  set ::custom_nfail -1
49262765a7Sdan  proc custom_injectstart {iFail} {
50262765a7Sdan    set ::custom_ifail $iFail
51262765a7Sdan    set ::custom_nfail 0
52262765a7Sdan  }
53262765a7Sdan  proc custom_injectstop {} {
54262765a7Sdan    set ::custom_ifail -1
55262765a7Sdan    return $::custom_nfail
56262765a7Sdan  }
57262765a7Sdan}
58262765a7Sdanproc uninstall_custom_faultsim {} {
59262765a7Sdan  unset -nocomplain ::FAULTSIM(custom)
60262765a7Sdan}
61262765a7Sdan
62262765a7Sdan
635279112eSdan#-------------------------------------------------------------------------
645279112eSdan# These tests - indexfault-1.* - Build an index on a smallish table with
655279112eSdan# all different kinds of fault-injection. The CREATE INDEX is run once
665279112eSdan# with default options and once with a 50KB soft-heap-limit.
675279112eSdan#
685279112eSdando_execsql_test 1.0 {
695279112eSdan  BEGIN;
705279112eSdan    CREATE TABLE t1(x);
715279112eSdan    INSERT INTO t1 VALUES(randomblob(202));
725279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --     2
735279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --     4
745279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --     8
755279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --    16
765279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --    32
775279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --    64
785279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --   128
795279112eSdan    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --   256
805279112eSdan  COMMIT;
815279112eSdan}
825279112eSdanfaultsim_save_and_close
835279112eSdan
845279112eSdando_faultsim_test 1.1 -prep {
855279112eSdan  faultsim_restore_and_reopen
865279112eSdan} -body {
875279112eSdan  execsql { CREATE INDEX i1 ON t1(x) }
885279112eSdan  faultsim_test_result {0 {}}
895279112eSdan  faultsim_integrity_check
905279112eSdan}
915279112eSdanifcapable memorymanage {
925279112eSdan  set soft_limit [sqlite3_soft_heap_limit 50000]
935279112eSdan  do_faultsim_test 2.1 -prep {
945279112eSdan    faultsim_restore_and_reopen
955279112eSdan  } -body {
965279112eSdan    execsql { CREATE INDEX i1 ON t1(x) }
975279112eSdan    faultsim_test_result {0 {}}
985279112eSdan  }
995279112eSdan  sqlite3_soft_heap_limit $soft_limit
1005279112eSdan}
1015279112eSdan
1025279112eSdan#-------------------------------------------------------------------------
1035279112eSdan# These are similar to the indexfault-1.* tests, except they create an
1045279112eSdan# index with more than one column.
1055279112eSdan#
1065279112eSdansqlite3 db test.db
1075279112eSdando_execsql_test 2.0 {
1085279112eSdan  BEGIN;
1095279112eSdan    DROP TABLE IF EXISTS t1;
1105279112eSdan    CREATE TABLE t1(t,u,v,w,x,y,z);
1115279112eSdan    INSERT INTO t1 VALUES(
1125279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1135279112eSdan      randomblob(30), randomblob(30), randomblob(30)
1145279112eSdan    );
1155279112eSdan    INSERT INTO t1 SELECT
1165279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1175279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 2
1185279112eSdan    INSERT INTO t1 SELECT
1195279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1205279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 4
1215279112eSdan    INSERT INTO t1 SELECT
1225279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1235279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 8
1245279112eSdan    INSERT INTO t1 SELECT
1255279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1265279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 16
1275279112eSdan    INSERT INTO t1 SELECT
1285279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1295279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 32
1305279112eSdan    INSERT INTO t1 SELECT
1315279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1325279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 64
1335279112eSdan    INSERT INTO t1 SELECT
1345279112eSdan      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
1355279112eSdan      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 128
1365279112eSdan  COMMIT;
1375279112eSdan}
1385279112eSdanfaultsim_save_and_close
1395279112eSdan
1405279112eSdando_faultsim_test 2.1 -prep {
1415279112eSdan  faultsim_restore_and_reopen
1425279112eSdan} -body {
1435279112eSdan  execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) }
1445279112eSdan  faultsim_test_result {0 {}}
1455279112eSdan  faultsim_integrity_check
1465279112eSdan}
1475279112eSdanifcapable memorymanage {
1485279112eSdan  set soft_limit [sqlite3_soft_heap_limit 50000]
1495279112eSdan  do_faultsim_test 2.2 -prep {
1505279112eSdan    faultsim_restore_and_reopen
1515279112eSdan  } -body {
1525279112eSdan    execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) }
1535279112eSdan    faultsim_test_result {0 {}}
1545279112eSdan  }
1555279112eSdan  sqlite3_soft_heap_limit $soft_limit
1565279112eSdan}
1575279112eSdan
1585279112eSdan#-------------------------------------------------------------------------
1595279112eSdan# The following tests - indexfault-2.* - all attempt to build a index
1605279112eSdan# on table t1 in the main database with injected IO errors. Individual
1615279112eSdan# test cases work as follows:
1625279112eSdan#
1635279112eSdan#   3.1: IO errors injected into xOpen() calls.
1645279112eSdan#   3.2: As 7.1, but with a low (50KB) soft-heap-limit.
1655279112eSdan#
1665279112eSdan#   3.3: IO errors injected into the first 200 write() calls made on the
1675279112eSdan#        second temporary file.
1685279112eSdan#   3.4: As 7.3, but with a low (50KB) soft-heap-limit.
1695279112eSdan#
170262765a7Sdan#   3.5: After a certain amount of data has been read from the main database
171262765a7Sdan#        file (and written into the temporary b-tree), sqlite3_release_memory()
172262765a7Sdan#        is called to free as much memory as possible. This causes the temp
173262765a7Sdan#        b-tree to be flushed to disk. So that before its contents can be
174262765a7Sdan#        transfered to a PMA they must be read back from disk - creating extra
175262765a7Sdan#        opportunities for IO errors.
1765279112eSdan#
177262765a7Sdaninstall_custom_faultsim
1785279112eSdan
1795279112eSdan# Set up a table to build indexes on. Save the setup using the
1805279112eSdan# [faultsim_save_and_close] mechanism.
1815279112eSdan#
1825279112eSdansqlite3 db test.db
1835279112eSdando_execsql_test 3.0 {
1845279112eSdan  BEGIN;
1855279112eSdan    DROP TABLE IF EXISTS t1;
1865279112eSdan    CREATE TABLE t1(x);
1875279112eSdan    INSERT INTO t1 VALUES(randomblob(11000));
1885279112eSdan    INSERT INTO t1 SELECT randomblob(11001) FROM t1;     --     2
1895279112eSdan    INSERT INTO t1 SELECT randomblob(11002) FROM t1;     --     4
1905279112eSdan    INSERT INTO t1 SELECT randomblob(11003) FROM t1;     --     8
1915279112eSdan    INSERT INTO t1 SELECT randomblob(11004) FROM t1;     --    16
1925279112eSdan    INSERT INTO t1 SELECT randomblob(11005) FROM t1;     --    32
1935279112eSdan    INSERT INTO t1 SELECT randomblob(11006) FROM t1;     --    64
1945279112eSdan    INSERT INTO t1 SELECT randomblob(11007) FROM t1;     --   128
1955279112eSdan    INSERT INTO t1 SELECT randomblob(11008) FROM t1;     --   256
1965279112eSdan    INSERT INTO t1 SELECT randomblob(11009) FROM t1;     --   512
1975279112eSdan  COMMIT;
1985279112eSdan}
1995279112eSdanfaultsim_save_and_close
2005279112eSdan
2015279112eSdanset ::custom_filter xOpen
2025279112eSdanproc xCustom {args} {
2035279112eSdan  incr ::custom_ifail -1
2045279112eSdan  if {$::custom_ifail==0} {
2055279112eSdan    incr ::custom_nfail
2065279112eSdan    return "SQLITE_IOERR"
2075279112eSdan  }
2085279112eSdan  return "SQLITE_OK"
2095279112eSdan}
2105279112eSdando_faultsim_test 3.1 -faults custom -prep {
2115279112eSdan  faultsim_restore_and_reopen
2125279112eSdan} -body {
2135279112eSdan  execsql { CREATE INDEX i1 ON t1(x) }
2145279112eSdan  faultsim_test_result {0 {}}
2155279112eSdan}
2165279112eSdanifcapable memorymanage {
2175279112eSdan  set soft_limit [sqlite3_soft_heap_limit 50000]
2185279112eSdan  do_faultsim_test 3.2 -faults custom -prep {
2195279112eSdan    faultsim_restore_and_reopen
2205279112eSdan  } -body {
2215279112eSdan    execsql { CREATE INDEX i1 ON t1(x) }
2225279112eSdan    faultsim_test_result {0 {}}
2235279112eSdan  }
2245279112eSdan  sqlite3_soft_heap_limit $soft_limit
2255279112eSdan}
2265279112eSdan
2275279112eSdanset ::custom_filter {xOpen xWrite}
2285279112eSdanproc xCustom {method args} {
2295279112eSdan  if {$method == "xOpen"} {
2305279112eSdan    if {[lindex $args 0] == ""} {
2315279112eSdan      incr ::nTmpOpen 1
2325279112eSdan      if {$::nTmpOpen == 3} { return "failme" }
2335279112eSdan    }
2345279112eSdan    return "SQLITE_OK"
2355279112eSdan  }
2365279112eSdan  if {$::custom_ifail<200 && [lindex $args 1] == "failme"} {
2375279112eSdan    incr ::custom_ifail -1
2385279112eSdan    if {$::custom_ifail==0} {
2395279112eSdan      incr ::custom_nfail
2405279112eSdan      return "SQLITE_IOERR"
2415279112eSdan    }
2425279112eSdan  }
2435279112eSdan  return "SQLITE_OK"
2445279112eSdan}
2455279112eSdan
2465279112eSdando_faultsim_test 3.3 -faults custom -prep {
2475279112eSdan  faultsim_restore_and_reopen
2485279112eSdan  set ::nTmpOpen 0
2495279112eSdan} -body {
2505279112eSdan  execsql { CREATE INDEX i1 ON t1(x) }
2515279112eSdan  faultsim_test_result {0 {}}
2525279112eSdan}
2535279112eSdan
2545279112eSdanifcapable memorymanage {
2555279112eSdan  set soft_limit [sqlite3_soft_heap_limit 50000]
2565279112eSdan  do_faultsim_test 3.4 -faults custom -prep {
2575279112eSdan    faultsim_restore_and_reopen
2585279112eSdan    set ::nTmpOpen 0
2595279112eSdan  } -body {
2605279112eSdan    execsql { CREATE INDEX i1 ON t1(x) }
2615279112eSdan    faultsim_test_result {0 {}}
2625279112eSdan  }
2635279112eSdan  sqlite3_soft_heap_limit $soft_limit
2645279112eSdan}
2655279112eSdan
266262765a7Sdanuninstall_custom_faultsim
267262765a7Sdan
268262765a7Sdan#-------------------------------------------------------------------------
269262765a7Sdan# Test 4: After a certain amount of data has been read from the main database
270262765a7Sdan# file (and written into the temporary b-tree), sqlite3_release_memory() is
271262765a7Sdan# called to free as much memory as possible. This causes the temp b-tree to be
272262765a7Sdan# flushed to disk. So that before its contents can be transfered to a PMA they
273262765a7Sdan# must be read back from disk - creating extra opportunities for IO errors.
274262765a7Sdan#
275262765a7Sdaninstall_custom_faultsim
276262765a7Sdan
277262765a7Sdancatch { db close }
278262765a7Sdanforcedelete test.db
279262765a7Sdansqlite3 db test.db
280262765a7Sdan
281262765a7Sdando_execsql_test 4.0 {
282262765a7Sdan  BEGIN;
283262765a7Sdan    DROP TABLE IF EXISTS t1;
284262765a7Sdan    CREATE TABLE t1(x);
285262765a7Sdan    INSERT INTO t1 VALUES(randomblob(11000));
286262765a7Sdan    INSERT INTO t1 SELECT randomblob(11001) FROM t1;     --     2
287262765a7Sdan    INSERT INTO t1 SELECT randomblob(11002) FROM t1;     --     4
288262765a7Sdan    INSERT INTO t1 SELECT randomblob(11003) FROM t1;     --     8
289262765a7Sdan    INSERT INTO t1 SELECT randomblob(11004) FROM t1;     --    16
290262765a7Sdan    INSERT INTO t1 SELECT randomblob(11005) FROM t1;     --    32
291262765a7Sdan    INSERT INTO t1 SELECT randomblob(11005) FROM t1;     --    64
292262765a7Sdan  COMMIT;
293262765a7Sdan}
294262765a7Sdanfaultsim_save_and_close
295262765a7Sdan
296262765a7Sdantestvfs tvfs
297262765a7Sdantvfs script xRead
298262765a7Sdantvfs filter xRead
299262765a7Sdanset ::nRead 0
300262765a7Sdanproc xRead {method file args} {
301262765a7Sdan  if {[file tail $file] == "test.db"} { incr ::nRead }
302262765a7Sdan}
303262765a7Sdan
304262765a7Sdando_test 4.1 {
305262765a7Sdan  sqlite3 db test.db -vfs tvfs
306262765a7Sdan  execsql { CREATE INDEX i1 ON t1(x) }
307262765a7Sdan} {}
308262765a7Sdan
309262765a7Sdandb close
310262765a7Sdantvfs delete
311262765a7Sdan
312262765a7Sdanset ::custom_filter xRead
313262765a7Sdanproc xCustom {method file args} {
314262765a7Sdan  incr ::nReadCall
315262765a7Sdan  if {$::nReadCall >= ($::nRead/5)} {
316262765a7Sdan    if {$::nReadCall == ($::nRead/5)} {
317262765a7Sdan      set nByte [sqlite3_release_memory [expr 64*1024*1024]]
318262765a7Sdan      sqlite3_soft_heap_limit 20000
319262765a7Sdan    }
320262765a7Sdan    if {$file == ""} {
321262765a7Sdan      incr ::custom_ifail -1
322262765a7Sdan      if {$::custom_ifail==0} {
323262765a7Sdan        incr ::custom_nfail
324262765a7Sdan        return "SQLITE_IOERR"
325262765a7Sdan      }
326262765a7Sdan    }
327262765a7Sdan  }
328262765a7Sdan  return "SQLITE_OK"
329262765a7Sdan}
330262765a7Sdan
331262765a7Sdando_faultsim_test 4.2 -faults custom -prep {
332262765a7Sdan  faultsim_restore_and_reopen
333262765a7Sdan  set ::nReadCall 0
334262765a7Sdan  sqlite3_soft_heap_limit 0
335262765a7Sdan} -body {
336262765a7Sdan  execsql { CREATE INDEX i1 ON t1(x) }
337262765a7Sdan  faultsim_test_result {0 {}}
338262765a7Sdan}
339262765a7Sdan
340*480c572fSdrhdo_faultsim_test 5 -prep {
341*480c572fSdrh  reset_db
342*480c572fSdrh} -body {
343*480c572fSdrh  execsql {
344*480c572fSdrh CREATE TABLE reallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname(a PRIMARY KEY) WITHOUT ROWID;
345*480c572fSdrh  }
346*480c572fSdrh} -test {
347*480c572fSdrh  faultsim_test_result {0 {}}
348*480c572fSdrh}
349*480c572fSdrh
350262765a7Sdanuninstall_custom_faultsim
351262765a7Sdan
3525279112eSdanfinish_test
353