Annotation of embedaddon/sqlite3/test/journal2.test, revision 1.1.1.1

1.1       misho       1: # 2010 June 16
                      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: # This file implements regression tests for SQLite library. Specifically,
                     12: # it tests SQLite when using a VFS that claims the SAFE_DELETE property.
                     13: #
                     14: 
                     15: set testdir [file dirname $argv0]
                     16: source $testdir/tester.tcl
                     17: source $testdir/lock_common.tcl
                     18: source $testdir/malloc_common.tcl
                     19: db close
                     20: 
                     21: if {[permutation] == "inmemory_journal"} {
                     22:   finish_test
                     23:   return
                     24: }
                     25: 
                     26: set a_string_counter 1
                     27: proc a_string {n} {
                     28:   global a_string_counter
                     29:   incr a_string_counter
                     30:   string range [string repeat "${a_string_counter}." $n] 1 $n
                     31: }
                     32: 
                     33: # Create a [testvfs] and install it as the default VFS. Set the device
                     34: # characteristics flags to "SAFE_DELETE".
                     35: #
                     36: testvfs tvfs -default 1
                     37: tvfs devchar {undeletable_when_open powersafe_overwrite}
                     38: 
                     39: # Set up a hook so that each time a journal file is opened, closed or
                     40: # deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
                     41: # segment of the journal file-name (i.e. "test.db-journal") are appended to
                     42: # global list variable $::oplog.
                     43: #
                     44: tvfs filter {xOpen xClose xDelete}
                     45: tvfs script journal_op_catcher
                     46: proc journal_op_catcher {method filename args} {
                     47: 
                     48:   # If global variable ::tvfs_error_on_write is defined, then return an
                     49:   # IO error to every attempt to modify the file-system. Otherwise, return
                     50:   # SQLITE_OK.
                     51:   #
                     52:   if {[info exists ::tvfs_error_on_write]} {
                     53:     if {[lsearch {xDelete xWrite xTruncate} $method]>=0} {
                     54:       return SQLITE_IOERR 
                     55:     }
                     56:   }
                     57: 
                     58:   # The rest of this command only deals with xOpen(), xClose() and xDelete()
                     59:   # operations on journal files. If this invocation does not represent such
                     60:   # an operation, return with no further ado.
                     61:   #
                     62:   set f [file tail $filename]
                     63:   if {[string match *journal $f]==0} return
                     64:   if {[lsearch {xOpen xDelete xClose} $method]<0} return
                     65: 
                     66:   # Append a record of this operation to global list variable $::oplog.
                     67:   #
                     68:   lappend ::oplog $method $f
                     69: 
                     70:   # If this is an attempt to delete a journal file for which there exists
                     71:   # one ore more open handles, return an error. The code in test_vfs.c
                     72:   # will not invoke the xDelete method of the "real" VFS in this case.
                     73:   #
                     74:   if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
                     75:   switch -- $method {
                     76:     xOpen   { incr ::open_journals($f) +1 }
                     77:     xClose  { incr ::open_journals($f) -1 }
                     78:     xDelete { if {$::open_journals($f)>0} { return SQLITE_IOERR } }
                     79:   }
                     80: 
                     81:   return ""
                     82: }
                     83: 
                     84: 
                     85: do_test journal2-1.1 {
                     86:   set ::oplog [list]
                     87:   sqlite3 db test.db
                     88:   execsql { CREATE TABLE t1(a, b) }
                     89:   set ::oplog
                     90: } {xOpen test.db-journal xClose test.db-journal xDelete test.db-journal}
                     91: do_test journal2-1.2 {
                     92:   set ::oplog [list]
                     93:   execsql { 
                     94:     PRAGMA journal_mode = truncate;
                     95:     INSERT INTO t1 VALUES(1, 2);
                     96:   }
                     97:   set ::oplog
                     98: } {xOpen test.db-journal}
                     99: do_test journal2-1.3 {
                    100:   set ::oplog [list]
                    101:   execsql { INSERT INTO t1 VALUES(3, 4) }
                    102:   set ::oplog
                    103: } {}
                    104: do_test journal2-1.4 { execsql { SELECT * FROM t1 } } {1 2 3 4}
                    105: 
                    106: # Add a second connection. This connection attempts to commit data in
                    107: # journal_mode=DELETE mode. When it tries to delete the journal file,
                    108: # the VFS layer returns an IO error.
                    109: #
                    110: do_test journal2-1.5 {
                    111:   set ::oplog [list]
                    112:   sqlite3 db2 test.db
                    113:   execsql  { PRAGMA journal_mode = delete } db2
                    114:   catchsql { INSERT INTO t1 VALUES(5, 6)  } db2
                    115: } {1 {disk I/O error}}
                    116: do_test journal2-1.6 { file exists test.db-journal } 1
                    117: do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
                    118: do_test journal2-1.8 {
                    119:   execsql { PRAGMA journal_mode = truncate } db2
                    120:   execsql { INSERT INTO t1 VALUES(5, 6)  } db2
                    121: } {}
                    122: do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}
                    123: 
                    124: # Grow the database until it is reasonably large.
                    125: #
                    126: do_test journal2-1.10 {
                    127:   db2 close
                    128:   db func a_string a_string
                    129:   execsql {
                    130:     CREATE TABLE t2(a UNIQUE, b UNIQUE);
                    131:     INSERT INTO t2 VALUES(a_string(200), a_string(300));
                    132:     INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2;  --  2
                    133:     INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2;  --  4
                    134:     INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2;  --  8
                    135:     INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2;  -- 16
                    136:     INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2;  -- 32
                    137:     INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2;  -- 64
                    138:   }
                    139:   file size test.db-journal
                    140: } {0}
                    141: do_test journal2-1.11 {
                    142:   set sz [expr [file size test.db] / 1024]
                    143:   expr {$sz>120 && $sz<200}
                    144: } 1
                    145: 
                    146: # Using new connection [db2] (with journal_mode=DELETE), write a lot of
                    147: # data to the database. So that many pages within the database file are
                    148: # modified before the transaction is committed.
                    149: #
                    150: # Then, enable simulated IO errors in all calls to xDelete, xWrite
                    151: # and xTruncate before committing the transaction and closing the 
                    152: # database file. From the point of view of other file-system users, it
                    153: # appears as if the process hosting [db2] unexpectedly exited.
                    154: # 
                    155: do_test journal2-1.12 {
                    156:   sqlite3 db2 test.db
                    157:   execsql {
                    158:     PRAGMA cache_size = 10;
                    159:     BEGIN;
                    160:       INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2;  -- 128
                    161:   } db2
                    162: } {}
                    163: do_test journal2-1.13 {
                    164:   tvfs filter {xOpen xClose xDelete xWrite xTruncate}
                    165:   set ::tvfs_error_on_write 1
                    166:   catchsql { COMMIT } db2
                    167: } {1 {disk I/O error}}
                    168: db2 close
                    169: unset ::tvfs_error_on_write
                    170: forcecopy test.db testX.db
                    171: 
                    172: do_test journal2-1.14 { file exists test.db-journal } 1
                    173: do_test journal2-1.15 {
                    174:   execsql {
                    175:     SELECT count(*) FROM t2;
                    176:     PRAGMA integrity_check;
                    177:   }
                    178: } {64 ok}
                    179: 
                    180: # This block checks that in the test case above, connection [db2] really
                    181: # did begin writing to the database file before it hit IO errors. If
                    182: # this is true, then the copy of the database file made before [db]
                    183: # rolled back the hot journal should fail the integrity-check.
                    184: #
                    185: do_test journal2-1.16 {
                    186:   set sz [expr [file size testX.db] / 1024]
                    187:   expr {$sz>240 && $sz<400}
                    188: } 1
                    189: do_test journal2-1.17 {
                    190:   expr {[catchsql { PRAGMA integrity_check } db] == "0 ok"}
                    191: } {1}
                    192: do_test journal2-1.20 {
                    193:   sqlite3 db2 testX.db
                    194:   expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
                    195: } {0}
                    196: do_test journal2-1.21 {
                    197:   db2 close
                    198: } {}
                    199: db close
                    200: 
                    201: #-------------------------------------------------------------------------
                    202: # Test that it is possible to switch from journal_mode=truncate to
                    203: # journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and
                    204: # delete the journal file when committing the transaction that switches
                    205: # the system to WAL mode.
                    206: #
                    207: ifcapable wal {
                    208:   do_test journal2-2.1 {
                    209:     faultsim_delete_and_reopen
                    210:     set ::oplog [list]
                    211:     execsql { PRAGMA journal_mode = persist }
                    212:     set ::oplog
                    213:   } {}
                    214:   do_test journal2-2.2 {
                    215:     execsql { 
                    216:       CREATE TABLE t1(x);
                    217:       INSERT INTO t1 VALUES(3.14159);
                    218:     }
                    219:     set ::oplog
                    220:   } {xOpen test.db-journal}
                    221:   do_test journal2-2.3 {
                    222:     expr {[file size test.db-journal] > 512}
                    223:   } {1}
                    224:   do_test journal2-2.4 {
                    225:     set ::oplog [list]
                    226:     execsql { PRAGMA journal_mode = WAL }
                    227:     set ::oplog
                    228:   } {xClose test.db-journal xDelete test.db-journal}
                    229:   db close
                    230: }
                    231: 
                    232: tvfs delete
                    233: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>