gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/indexfault.test (about)

     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  do_faultsim_test 5 -prep {
   341    reset_db
   342  } -body {
   343    execsql { 
   344   CREATE TABLE reallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname(a PRIMARY KEY) WITHOUT ROWID;
   345    }
   346  } -test {
   347    faultsim_test_result {0 {}} 
   348  }
   349  
   350  uninstall_custom_faultsim
   351  
   352  finish_test