/ Check-in [0e6defa6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add fault-injection and other tests (and fixes) to improve coverage of vdbesort.c.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 0e6defa6aa540b413ea3f4bb6dcd86364d547067
User & Date: dan 2011-08-08 16:44:25
Context
2011-08-08
19:26
Remove redundant parameter from vdbeSorterInitMerge() in vdbesort.c. check-in: eec8c0df user: dan tags: experimental
16:44
Add fault-injection and other tests (and fixes) to improve coverage of vdbesort.c. check-in: 0e6defa6 user: dan tags: experimental
2011-08-06
15:09
Fix a problem with building large indexes introduced by the previous commit. check-in: 038ec9ea user: dan tags: experimental
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbesort.c.

   392    392         /* Write the size of the record in bytes to the output file */
   393    393         (void)sqlite3BtreeKeySize(pCsr->pCursor, &nKey);
   394    394         rc = vdbeSorterWriteVarint(pSorter->pTemp1, nKey, &iWriteOff);
   395    395   
   396    396         /* Make sure the aMalloc[] buffer is large enough for the record */
   397    397         if( rc==SQLITE_OK && nKey>nMalloc ){
   398    398           aMalloc = sqlite3DbReallocOrFree(db, aMalloc, nKey);
   399         -        if( !aMalloc ){
   400         -          rc = SQLITE_NOMEM;
          399  +        if( !aMalloc ){ 
          400  +          rc = SQLITE_NOMEM; 
          401  +        }else{
          402  +          nMalloc = nKey;
   401    403           }
   402    404         }
   403    405   
   404    406         /* Write the record itself to the output file */
   405    407         if( rc==SQLITE_OK ){
   406    408           rc = sqlite3BtreeKey(pCsr->pCursor, 0, nKey, aMalloc);
   407    409           if( rc==SQLITE_OK ){
   408    410             rc = sqlite3OsWrite(pSorter->pTemp1, aMalloc, nKey, iWriteOff);
   409    411             iWriteOff += nKey;
   410    412           }
   411    413         }
   412    414   
          415  +      if( rc!=SQLITE_OK ) break;
   413    416       }
   414    417   
   415         -    assert( pSorter->nBtree==(
          418  +    assert( rc!=SQLITE_OK || pSorter->nBtree==(
   416    419             iWriteOff-pSorter->iWriteOff-sqlite3VarintLen(pSorter->nBtree)
   417    420       ));
   418    421       pSorter->iWriteOff = iWriteOff;
   419    422       sqlite3DbFree(db, aMalloc);
   420    423     }
   421    424   
   422    425     pSorter->nBtree = 0;
................................................................................
   644    647   ** Copy the current sorter key into the memory cell pOut.
   645    648   */
   646    649   int sqlite3VdbeSorterRowkey(sqlite3 *db, VdbeCursor *pCsr, Mem *pOut){
   647    650     VdbeSorter *pSorter = pCsr->pSorter;
   648    651     VdbeSorterIter *pIter;
   649    652   
   650    653     pIter = &pSorter->aIter[ pSorter->aTree[1] ];
          654  +
          655  +  /* Coverage testing note: As things are currently, this call will always
          656  +  ** succeed. This is because the memory cell passed by the VDBE layer 
          657  +  ** happens to be the same one as was used to assemble the keys before they
          658  +  ** were passed to the sorter - meaning it is always large enough for the
          659  +  ** largest key. But this could change very easily, so we leave the call
          660  +  ** to sqlite3VdbeMemGrow() in. */
   651    661     if( sqlite3VdbeMemGrow(pOut, pIter->nKey, 0) ){
   652    662       return SQLITE_NOMEM;
   653    663     }
   654    664     pOut->n = pIter->nKey;
   655    665     MemSetTypeFlag(pOut, MEM_Blob);
   656    666     memcpy(pOut->z, pIter->aKey, pIter->nKey);
   657    667   
   658    668     return SQLITE_OK;
   659    669   }
   660    670   

Changes to test/index4.test.

    62     62     do_execsql_test 1.5 {
    63     63       PRAGMA integrity_check 
    64     64     } {ok}
    65     65   
    66     66     sqlite3_soft_heap_limit $soft_limit
    67     67   }
    68     68   
           69  +
           70  +do_execsql_test 1.6 {
           71  +  BEGIN;
           72  +    DROP TABLE t1;
           73  +    CREATE TABLE t1(x);
           74  +    INSERT INTO t1 VALUES('a');
           75  +    INSERT INTO t1 VALUES('b');
           76  +    INSERT INTO t1 VALUES('c');
           77  +    INSERT INTO t1 VALUES('d');
           78  +    INSERT INTO t1 VALUES('e');
           79  +    INSERT INTO t1 VALUES('f');
           80  +    INSERT INTO t1 VALUES('g');
           81  +    INSERT INTO t1 VALUES(NULL);
           82  +    INSERT INTO t1 SELECT randomblob(1202) FROM t1;     --    16
           83  +    INSERT INTO t1 SELECT randomblob(2202) FROM t1;     --    32
           84  +    INSERT INTO t1 SELECT randomblob(3202) FROM t1;     --    64
           85  +    INSERT INTO t1 SELECT randomblob(4202) FROM t1;     --   128
           86  +    INSERT INTO t1 SELECT randomblob(5202) FROM t1;     --   256
           87  +  COMMIT;
           88  +  CREATE INDEX i1 ON t1(x); 
           89  +  PRAGMA integrity_check
           90  +} {ok}
           91  +
           92  +do_execsql_test 1.7 {
           93  +  BEGIN;
           94  +    DROP TABLE t1;
           95  +    CREATE TABLE t1(x);
           96  +    INSERT INTO t1 VALUES('a');
           97  +  COMMIT;
           98  +  CREATE INDEX i1 ON t1(x); 
           99  +  PRAGMA integrity_check
          100  +} {ok}
          101  +
          102  +do_execsql_test 1.8 {
          103  +  BEGIN;
          104  +    DROP TABLE t1;
          105  +    CREATE TABLE t1(x);
          106  +  COMMIT;
          107  +  CREATE INDEX i1 ON t1(x); 
          108  +  PRAGMA integrity_check
          109  +} {ok}
          110  +
    69    111   
    70    112   finish_test

Added test/indexfault.test.

            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  +set testprefix indexfault
           19  +
           20  +#-------------------------------------------------------------------------
           21  +# These tests - indexfault-1.* - Build an index on a smallish table with
           22  +# all different kinds of fault-injection. The CREATE INDEX is run once
           23  +# with default options and once with a 50KB soft-heap-limit.
           24  +#
           25  +do_execsql_test 1.0 {
           26  +  BEGIN;
           27  +    CREATE TABLE t1(x);
           28  +    INSERT INTO t1 VALUES(randomblob(202));
           29  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --     2
           30  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --     4
           31  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --     8
           32  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --    16
           33  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --    32
           34  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --    64
           35  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --   128
           36  +    INSERT INTO t1 SELECT randomblob(202) FROM t1;     --   256
           37  +  COMMIT;
           38  +}
           39  +faultsim_save_and_close
           40  +
           41  +do_faultsim_test 1.1 -prep {
           42  +  faultsim_restore_and_reopen
           43  +} -body {
           44  +  execsql { CREATE INDEX i1 ON t1(x) }
           45  +  faultsim_test_result {0 {}} 
           46  +  faultsim_integrity_check
           47  +}
           48  +ifcapable memorymanage {
           49  +  set soft_limit [sqlite3_soft_heap_limit 50000]
           50  +  do_faultsim_test 2.1 -prep {
           51  +    faultsim_restore_and_reopen
           52  +  } -body {
           53  +    execsql { CREATE INDEX i1 ON t1(x) }
           54  +    faultsim_test_result {0 {}} 
           55  +  }
           56  +  sqlite3_soft_heap_limit $soft_limit
           57  +}
           58  +
           59  +#-------------------------------------------------------------------------
           60  +# These are similar to the indexfault-1.* tests, except they create an
           61  +# index with more than one column.
           62  +#
           63  +sqlite3 db test.db
           64  +do_execsql_test 2.0 {
           65  +  BEGIN;
           66  +    DROP TABLE IF EXISTS t1;
           67  +    CREATE TABLE t1(t,u,v,w,x,y,z);
           68  +    INSERT INTO t1 VALUES(
           69  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           70  +      randomblob(30), randomblob(30), randomblob(30)
           71  +    );
           72  +    INSERT INTO t1 SELECT 
           73  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           74  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 2
           75  +    INSERT INTO t1 SELECT 
           76  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           77  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 4
           78  +    INSERT INTO t1 SELECT 
           79  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           80  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 8
           81  +    INSERT INTO t1 SELECT 
           82  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           83  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 16
           84  +    INSERT INTO t1 SELECT 
           85  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           86  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 32
           87  +    INSERT INTO t1 SELECT 
           88  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           89  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 64
           90  +    INSERT INTO t1 SELECT 
           91  +      randomblob(30), randomblob(30), randomblob(30), randomblob(30),
           92  +      randomblob(30), randomblob(30), randomblob(30) FROM t1;         -- 128
           93  +  COMMIT;
           94  +}
           95  +faultsim_save_and_close
           96  +
           97  +do_faultsim_test 2.1 -prep {
           98  +  faultsim_restore_and_reopen
           99  +} -body {
          100  +  execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) }
          101  +  faultsim_test_result {0 {}} 
          102  +  faultsim_integrity_check
          103  +}
          104  +ifcapable memorymanage {
          105  +  set soft_limit [sqlite3_soft_heap_limit 50000]
          106  +  do_faultsim_test 2.2 -prep {
          107  +    faultsim_restore_and_reopen
          108  +  } -body {
          109  +    execsql { CREATE INDEX i1 ON t1(t,u,v,w,x,y,z) }
          110  +    faultsim_test_result {0 {}} 
          111  +  }
          112  +  sqlite3_soft_heap_limit $soft_limit
          113  +}
          114  +
          115  +#-------------------------------------------------------------------------
          116  +# The following tests - indexfault-2.* - all attempt to build a index
          117  +# on table t1 in the main database with injected IO errors. Individual
          118  +# test cases work as follows:
          119  +#
          120  +#   3.1: IO errors injected into xOpen() calls.
          121  +#   3.2: As 7.1, but with a low (50KB) soft-heap-limit.
          122  +#
          123  +#   3.3: IO errors injected into the first 200 write() calls made on the
          124  +#        second temporary file.
          125  +#   3.4: As 7.3, but with a low (50KB) soft-heap-limit.
          126  +#
          127  +#
          128  +
          129  +# Set up the custom fault-injector. This is further configured by using
          130  +# different values for $::custom_filter and different implementations
          131  +# of Tcl proc [xCustom] for each test case.
          132  +#
          133  +set FAULTSIM(custom)            [list      \
          134  +  -injectinstall   custom_injectinstall    \
          135  +  -injectstart     custom_injectstart      \
          136  +  -injectstop      custom_injectstop       \
          137  +  -injecterrlist   {{1 {disk I/O error}}}  \
          138  +  -injectuninstall custom_injectuninstall  \
          139  +]
          140  +proc custom_injectinstall {} {
          141  +  testvfs shmfault -default true
          142  +  shmfault filter $::custom_filter
          143  +  shmfault script xCustom
          144  +}
          145  +proc custom_injectuninstall {} {
          146  +  catch {db  close}
          147  +  catch {db2 close}
          148  +  shmfault delete
          149  +}
          150  +set ::custom_ifail -1
          151  +set ::custom_nfail -1
          152  +proc custom_injectstart {iFail} {
          153  +  set ::custom_ifail $iFail
          154  +  set ::custom_nfail 0
          155  +}
          156  +proc custom_injectstop {} {
          157  +  set ::custom_ifail -1
          158  +  return $::custom_nfail
          159  +}
          160  +
          161  +# Set up a table to build indexes on. Save the setup using the 
          162  +# [faultsim_save_and_close] mechanism.
          163  +# 
          164  +sqlite3 db test.db
          165  +do_execsql_test 3.0 {
          166  +  BEGIN;
          167  +    DROP TABLE IF EXISTS t1;
          168  +    CREATE TABLE t1(x);
          169  +    INSERT INTO t1 VALUES(randomblob(11000));
          170  +    INSERT INTO t1 SELECT randomblob(11001) FROM t1;     --     2
          171  +    INSERT INTO t1 SELECT randomblob(11002) FROM t1;     --     4
          172  +    INSERT INTO t1 SELECT randomblob(11003) FROM t1;     --     8
          173  +    INSERT INTO t1 SELECT randomblob(11004) FROM t1;     --    16
          174  +    INSERT INTO t1 SELECT randomblob(11005) FROM t1;     --    32
          175  +    INSERT INTO t1 SELECT randomblob(11006) FROM t1;     --    64
          176  +    INSERT INTO t1 SELECT randomblob(11007) FROM t1;     --   128
          177  +    INSERT INTO t1 SELECT randomblob(11008) FROM t1;     --   256
          178  +    INSERT INTO t1 SELECT randomblob(11009) FROM t1;     --   512
          179  +  COMMIT;
          180  +}
          181  +faultsim_save_and_close
          182  +
          183  +set ::custom_filter xOpen
          184  +proc xCustom {args} {
          185  +  incr ::custom_ifail -1
          186  +  if {$::custom_ifail==0} {
          187  +    incr ::custom_nfail
          188  +    return "SQLITE_IOERR"
          189  +  }
          190  +  return "SQLITE_OK"
          191  +}
          192  +do_faultsim_test 3.1 -faults custom -prep {
          193  +  faultsim_restore_and_reopen
          194  +} -body {
          195  +  execsql { CREATE INDEX i1 ON t1(x) }
          196  +  faultsim_test_result {0 {}} 
          197  +}
          198  +ifcapable memorymanage {
          199  +  set soft_limit [sqlite3_soft_heap_limit 50000]
          200  +  do_faultsim_test 3.2 -faults custom -prep {
          201  +    faultsim_restore_and_reopen
          202  +  } -body {
          203  +    execsql { CREATE INDEX i1 ON t1(x) }
          204  +    faultsim_test_result {0 {}} 
          205  +  }
          206  +  sqlite3_soft_heap_limit $soft_limit
          207  +}
          208  +
          209  +set ::custom_filter {xOpen xWrite}
          210  +proc xCustom {method args} {
          211  +  if {$method == "xOpen"} {
          212  +    if {[lindex $args 0] == ""} {
          213  +      incr ::nTmpOpen 1
          214  +      if {$::nTmpOpen == 3} { return "failme" }
          215  +    }
          216  +    return "SQLITE_OK"
          217  +  }
          218  +  if {$::custom_ifail<200 && [lindex $args 1] == "failme"} {
          219  +    incr ::custom_ifail -1
          220  +    if {$::custom_ifail==0} {
          221  +      incr ::custom_nfail
          222  +      return "SQLITE_IOERR"
          223  +    }
          224  +  }
          225  +  return "SQLITE_OK"
          226  +}
          227  +
          228  +do_faultsim_test 3.3 -faults custom -prep {
          229  +  faultsim_restore_and_reopen
          230  +  set ::nTmpOpen 0
          231  +} -body {
          232  +  execsql { CREATE INDEX i1 ON t1(x) }
          233  +  faultsim_test_result {0 {}} 
          234  +}
          235  +
          236  +ifcapable memorymanage {
          237  +  set soft_limit [sqlite3_soft_heap_limit 50000]
          238  +  do_faultsim_test 3.4 -faults custom -prep {
          239  +    faultsim_restore_and_reopen
          240  +    set ::nTmpOpen 0
          241  +  } -body {
          242  +    execsql { CREATE INDEX i1 ON t1(x) }
          243  +    faultsim_test_result {0 {}} 
          244  +  }
          245  +  sqlite3_soft_heap_limit $soft_limit
          246  +}
          247  +
          248  +finish_test

Changes to test/permutations.test.

   107    107     misc7.test mutex2.test notify2.test onefile.test pagerfault2.test 
   108    108     savepoint4.test savepoint6.test select9.test 
   109    109     speed1.test speed1p.test speed2.test speed3.test speed4.test 
   110    110     speed4p.test sqllimits1.test tkt2686.test thread001.test thread002.test
   111    111     thread003.test thread004.test thread005.test trans2.test vacuum3.test 
   112    112     incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test
   113    113     vtab_err.test walslow.test walcrash.test 
   114         -  walthread.test rtree3.test
          114  +  walthread.test rtree3.test indexfault.test
   115    115   }]
   116    116   if {[info exists ::env(QUICKTEST_INCLUDE)]} {
   117    117     set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
   118    118   }
   119    119   
   120    120   #############################################################################
   121    121   # Start of tests