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

     1  # 2010 May 25
     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  
    14  set testdir [file dirname $argv0]
    15  source $testdir/tester.tcl
    16  source $testdir/lock_common.tcl
    17  source $testdir/wal_common.tcl
    18  ifcapable !wal {finish_test ; return }
    19  
    20  
    21  #-------------------------------------------------------------------------
    22  # This test case demonstrates a flaw in the wal-index manipulation that
    23  # existed at one point: If a process crashes mid-transaction, it may have
    24  # already added some entries to one of the hash-tables in the wal-index.
    25  # If the transaction were to be explicitly rolled back at this point, the
    26  # hash-table entries would be removed as part of the rollback. However,
    27  # if the process crashes, the transaction is implicitly rolled back and
    28  # the rogue entries remain in the hash table.
    29  #
    30  # Normally, this causes no problem - readers can tell the difference 
    31  # between committed and uncommitted entries in the hash table. However,
    32  # if it happens often enough that all slots in the hash-table become 
    33  # non-zero, the next process that attempts to read or write the hash
    34  # table falls into an infinite loop.
    35  #
    36  # Even if run with an SQLite version affected by the bug, this test case
    37  # only goes into an infinite loop if SQLite is compiled without SQLITE_DEBUG
    38  # defined. If SQLITE_DEBUG is defined, the program is halted by a failing
    39  # assert() before entering the infinite loop.
    40  #
    41  # walcrash2-1.1: Create a database. Commit a transaction that adds 8 frames
    42  #                to the WAL (and 8 entry to the first hash-table in the 
    43  #                wal-index).
    44  #
    45  # walcrash2-1.2: Have an external process open a transaction, add 8 entries
    46  #                to the wal-index hash-table, then crash. Repeat this 1023
    47  #                times (so that the wal-index contains 8192 entries - all
    48  #                slots are non-zero).
    49  #
    50  # walcrash2-1.3: Using a new database connection, attempt to query the 
    51  #                database. This should cause the process to go into the
    52  #                infinite loop.
    53  #
    54  do_test walcrash2-1.1 {
    55    execsql {
    56      PRAGMA page_size = 1024;
    57      PRAGMA auto_vacuum = off;
    58      PRAGMA journal_mode = WAL;
    59      PRAGMA synchronous = NORMAL;
    60      BEGIN;
    61        CREATE TABLE t1(x);
    62        CREATE TABLE t2(x);
    63        CREATE TABLE t3(x);
    64        CREATE TABLE t4(x);
    65        CREATE TABLE t5(x);
    66        CREATE TABLE t6(x);
    67        CREATE TABLE t7(x);
    68      COMMIT;
    69    }
    70    file size test.db-wal
    71  } [wal_file_size 8 1024] 
    72  for {set nEntry 8} {$nEntry < 8192} {incr nEntry 8} {
    73    do_test walcrash2-1.2.[expr $nEntry/8] {
    74      set C [launch_testfixture]
    75      testfixture $C {
    76        sqlite3 db test.db
    77        db eval {
    78          PRAGMA cache_size = 15;
    79          BEGIN;
    80            INSERT INTO t1 VALUES(randomblob(900));         --  1 row,  1  page
    81            INSERT INTO t1 SELECT * FROM t1;                --  2 rows, 3  pages
    82            INSERT INTO t1 SELECT * FROM t1;                --  4 rows, 5  pages
    83            INSERT INTO t1 SELECT * FROM t1;                --  8 rows, 9  pages
    84            INSERT INTO t1 SELECT * FROM t1;                -- 16 rows, 17 pages
    85            INSERT INTO t1 SELECT * FROM t1 LIMIT 3;        -- 20 rows, 20 pages
    86        }
    87      } 
    88      close $C
    89      file size test.db-wal
    90    } [wal_file_size 16 1024]
    91  }
    92  do_test walcrash2-1.3 {
    93    sqlite3 db2 test.db
    94    execsql { SELECT count(*) FROM t1 } db2
    95  } {0}
    96  catch { db2 close }
    97  
    98  finish_test