File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / test / journal2.test
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:16 2012 UTC (12 years, 10 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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>