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

1.1       misho       1: # 2010 April 13
                      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.  The
                     12: # focus of this file is testing the operation of the library in
                     13: # "PRAGMA journal_mode=WAL" mode.
                     14: #
                     15: 
                     16: set testdir [file dirname $argv0]
                     17: source $testdir/tester.tcl
                     18: source $testdir/lock_common.tcl
                     19: source $testdir/wal_common.tcl
                     20: source $testdir/malloc_common.tcl
                     21: ifcapable !wal {finish_test ; return }
                     22: 
                     23: set a_string_counter 1
                     24: proc a_string {n} {
                     25:   global a_string_counter
                     26:   incr a_string_counter
                     27:   string range [string repeat "${a_string_counter}." $n] 1 $n
                     28: }
                     29: db func a_string a_string
                     30: 
                     31: #-------------------------------------------------------------------------
                     32: # When a rollback or savepoint rollback occurs, the client may remove
                     33: # elements from one of the hash tables in the wal-index. This block
                     34: # of test cases tests that nothing appears to go wrong when this is
                     35: # done.
                     36: #
                     37: do_test wal3-1.0 {
                     38:   execsql {
                     39:     PRAGMA cache_size = 2000;
                     40:     PRAGMA page_size = 1024;
                     41:     PRAGMA auto_vacuum = off;
                     42:     PRAGMA synchronous = normal;
                     43:     PRAGMA journal_mode = WAL;
                     44:     PRAGMA wal_autocheckpoint = 0;
                     45:     BEGIN;
                     46:       CREATE TABLE t1(x);
                     47:       INSERT INTO t1 VALUES( a_string(800) );                  /*    1 */
                     48:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*    2 */
                     49:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*    4 */
                     50:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*    8 */
                     51:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*   16 */
                     52:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*   32 */
                     53:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*   64 */
                     54:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*  128*/
                     55:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*  256 */
                     56:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /*  512 */
                     57:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /* 1024 */
                     58:       INSERT INTO t1 SELECT a_string(800) FROM t1;             /* 2048 */
                     59:       INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 1970;  /* 4018 */
                     60:     COMMIT;
                     61:     PRAGMA cache_size = 10;
                     62:   }
                     63:   wal_frame_count test.db-wal 1024
                     64: } 4056
                     65: 
                     66: for {set i 1} {$i < 50} {incr i} {
                     67: 
                     68:   do_test wal3-1.$i.1 {
                     69:     set str [a_string 800]
                     70:     execsql { UPDATE t1 SET x = $str WHERE rowid = $i }
                     71:     lappend L [wal_frame_count test.db-wal 1024]
                     72:     execsql {
                     73:       BEGIN;
                     74:         INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 100;
                     75:       ROLLBACK;
                     76:       PRAGMA integrity_check;
                     77:     }
                     78:   } {ok}
                     79: 
                     80:   # Check that everything looks OK from the point of view of an 
                     81:   # external connection.
                     82:   #
                     83:   sqlite3 db2 test.db
                     84:   do_test wal3-1.$i.2 {
                     85:     execsql { SELECT count(*) FROM t1 } db2
                     86:   } 4018
                     87:   do_test wal3-1.$i.3 {
                     88:     execsql { SELECT x FROM t1 WHERE rowid = $i }
                     89:   } $str
                     90:   do_test wal3-1.$i.4 {
                     91:     execsql { PRAGMA integrity_check } db2
                     92:   } {ok}
                     93:   db2 close
                     94:   
                     95:   # Check that the file-system in its current state can be recovered.
                     96:   # 
                     97:   forcecopy test.db test2.db
                     98:   forcecopy test.db-wal test2.db-wal
                     99:   forcedelete test2.db-journal
                    100:   sqlite3 db2 test2.db
                    101:   do_test wal3-1.$i.5 {
                    102:     execsql { SELECT count(*) FROM t1 } db2
                    103:   } 4018
                    104:   do_test wal3-1.$i.6 {
                    105:     execsql { SELECT x FROM t1 WHERE rowid = $i }
                    106:   } $str
                    107:   do_test wal3-1.$i.7 {
                    108:     execsql { PRAGMA integrity_check } db2
                    109:   } {ok}
                    110:   db2 close
                    111: }
                    112: 
                    113: proc byte_is_zero {file offset} {
                    114:   if {[file size test.db] <= $offset} { return 1 }
                    115:   expr { [hexio_read $file $offset 1] == "00" }
                    116: }
                    117: 
                    118: do_multiclient_test i {
                    119: 
                    120:   set testname(1) multiproc
                    121:   set testname(2) singleproc
                    122:   set tn $testname($i)
                    123: 
                    124:   do_test wal3-2.$tn.1 {
                    125:     sql1 { 
                    126:       PRAGMA page_size = 1024;
                    127:       PRAGMA journal_mode = WAL;
                    128:     }
                    129:     sql1 {
                    130:       CREATE TABLE t1(a, b);
                    131:       INSERT INTO t1 VALUES(1, 'one');
                    132:       BEGIN;
                    133:         SELECT * FROM t1;
                    134:     }
                    135:   } {1 one}
                    136:   do_test wal3-2.$tn.2 {
                    137:     sql2 {
                    138:       CREATE TABLE t2(a, b);
                    139:       INSERT INTO t2 VALUES(2, 'two');
                    140:       BEGIN;
                    141:         SELECT * FROM t2;
                    142:     }
                    143:   } {2 two}
                    144:   do_test wal3-2.$tn.3 {
                    145:     sql3 {
                    146:       CREATE TABLE t3(a, b);
                    147:       INSERT INTO t3 VALUES(3, 'three');
                    148:       BEGIN;
                    149:         SELECT * FROM t3;
                    150:     }
                    151:   } {3 three}
                    152: 
                    153:   # Try to checkpoint the database using [db]. It should be possible to
                    154:   # checkpoint everything except the table added by [db3] (checkpointing
                    155:   # these frames would clobber the snapshot currently being used by [db2]).
                    156:   #
                    157:   # After [db2] has committed, a checkpoint can copy the entire log to the
                    158:   # database file. Checkpointing after [db3] has committed is therefore a
                    159:   # no-op, as the entire log has already been backfilled.
                    160:   #
                    161:   do_test wal3-2.$tn.4 {
                    162:     sql1 {
                    163:       COMMIT;
                    164:       PRAGMA wal_checkpoint;
                    165:     }
                    166:     byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]
                    167:   } {1}
                    168:   do_test wal3-2.$tn.5 {
                    169:     sql2 {
                    170:       COMMIT;
                    171:       PRAGMA wal_checkpoint;
                    172:     }
                    173:     list [byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]]   \
                    174:          [byte_is_zero test.db [expr $AUTOVACUUM ? 5*1024 : 4*1024]]
                    175:   } {0 1}
                    176:   do_test wal3-2.$tn.6 {
                    177:     sql3 {
                    178:       COMMIT;
                    179:       PRAGMA wal_checkpoint;
                    180:     }
                    181:     list [byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]]   \
                    182:          [byte_is_zero test.db [expr $AUTOVACUUM ? 5*1024 : 4*1024]]
                    183:   } {0 1}
                    184: }
                    185: catch {db close}
                    186: 
                    187: #-------------------------------------------------------------------------
                    188: # Test that that for the simple test:
                    189: #
                    190: #   CREATE TABLE x(y);
                    191: #   INSERT INTO x VALUES('z');
                    192: #   PRAGMA wal_checkpoint;
                    193: #
                    194: # in WAL mode the xSync method is invoked as expected for each of
                    195: # synchronous=off, synchronous=normal and synchronous=full.
                    196: #
                    197: foreach {tn syncmode synccount} {
                    198:   1 off     
                    199:     {}
                    200:   2 normal  
                    201:     {test.db-wal normal test.db normal}
                    202:   3 full    
                    203:     {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
                    204: } {
                    205: 
                    206:   proc sync_counter {args} { 
                    207:     foreach {method filename id flags} $args break
                    208:     lappend ::syncs [file tail $filename] $flags
                    209:   }
                    210:   do_test wal3-3.$tn {
                    211:     forcedelete test.db test.db-wal test.db-journal
                    212:   
                    213:     testvfs T
                    214:     T filter {} 
                    215:     T script sync_counter
                    216:     sqlite3 db test.db -vfs T
                    217:   
                    218:     execsql "PRAGMA synchronous = $syncmode"
                    219:     execsql { PRAGMA journal_mode = WAL }
                    220:     execsql { CREATE TABLE filler(a,b,c); }
                    221: 
                    222:     set ::syncs [list]
                    223:     T filter xSync
                    224:     execsql {
                    225:       CREATE TABLE x(y);
                    226:       INSERT INTO x VALUES('z');
                    227:       PRAGMA wal_checkpoint;
                    228:     }
                    229:     T filter {}
                    230:     set ::syncs
                    231:   } $synccount
                    232: 
                    233:   db close
                    234:   T delete
                    235: }
                    236: 
                    237: #-------------------------------------------------------------------------
                    238: # When recovering the contents of a WAL file, a process obtains the WRITER
                    239: # lock, then locks all other bytes before commencing recovery. If it fails
                    240: # to lock all other bytes (because some other process is holding a read
                    241: # lock) it should retry up to 100 times. Then return SQLITE_PROTOCOL to the 
                    242: # caller. Test this (test case wal3-4.3).
                    243: #
                    244: # Also test the effect of hitting an SQLITE_BUSY while attempting to obtain
                    245: # the WRITER lock (should be the same). Test case wal3-4.4.
                    246: # 
                    247: proc lock_callback {method filename handle lock} {
                    248:   lappend ::locks $lock
                    249: }
                    250: do_test wal3-4.1 {
                    251:   testvfs T
                    252:   T filter xShmLock 
                    253:   T script lock_callback
                    254:   set ::locks [list]
                    255:   sqlite3 db test.db -vfs T
                    256:   execsql { SELECT * FROM x }
                    257:   lrange $::locks 0 3
                    258: } [list {0 1 lock exclusive} {1 7 lock exclusive}      \
                    259:         {1 7 unlock exclusive} {0 1 unlock exclusive}  \
                    260: ]
                    261: do_test wal3-4.2 {
                    262:   db close
                    263:   set ::locks [list]
                    264:   sqlite3 db test.db -vfs T
                    265:   execsql { SELECT * FROM x }
                    266:   lrange $::locks 0 3
                    267: } [list {0 1 lock exclusive} {1 7 lock exclusive}      \
                    268:         {1 7 unlock exclusive} {0 1 unlock exclusive}  \
                    269: ]
                    270: proc lock_callback {method filename handle lock} {
                    271:   if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY }
                    272:   return SQLITE_OK
                    273: }
                    274: puts "  Warning: This next test case causes SQLite to call xSleep(1) 100 times."
                    275: puts "  Normally this equates to a 100ms delay, but if SQLite is built on unix"
                    276: puts "  without HAVE_USLEEP defined, it may be 100 seconds."
                    277: do_test wal3-4.3 {
                    278:   db close
                    279:   set ::locks [list]
                    280:   sqlite3 db test.db -vfs T
                    281:   catchsql { SELECT * FROM x }
                    282: } {1 {locking protocol}}
                    283: 
                    284: puts "  Warning: Same again!"
                    285: proc lock_callback {method filename handle lock} {
                    286:   if {$lock == "0 1 lock exclusive"} { return SQLITE_BUSY }
                    287:   return SQLITE_OK
                    288: }
                    289: do_test wal3-4.4 {
                    290:   db close
                    291:   set ::locks [list]
                    292:   sqlite3 db test.db -vfs T
                    293:   catchsql { SELECT * FROM x }
                    294: } {1 {locking protocol}}
                    295: db close
                    296: T delete
                    297: 
                    298: 
                    299: #-------------------------------------------------------------------------
                    300: # Only one client may run recovery at a time. Test this mechanism.
                    301: #
                    302: # When client-2 tries to open a read transaction while client-1 is 
                    303: # running recovery, it fails to obtain a lock on an aReadMark[] slot
                    304: # (because they are all locked by recovery). It then tries to obtain
                    305: # a shared lock on the RECOVER lock to see if there really is a
                    306: # recovery running or not.
                    307: #
                    308: # This block of tests checks the effect of an SQLITE_BUSY or SQLITE_IOERR
                    309: # being returned when client-2 attempts a shared lock on the RECOVER byte.
                    310: #
                    311: # An SQLITE_BUSY should be converted to an SQLITE_BUSY_RECOVERY. An
                    312: # SQLITE_IOERR should be returned to the caller.
                    313: #
                    314: do_test wal3-5.1 {
                    315:   faultsim_delete_and_reopen
                    316:   execsql {
                    317:     PRAGMA journal_mode = WAL;
                    318:     CREATE TABLE t1(a, b);
                    319:     INSERT INTO t1 VALUES(1, 2);
                    320:     INSERT INTO t1 VALUES(3, 4);
                    321:   }
                    322:   faultsim_save_and_close
                    323: } {}
                    324: 
                    325: testvfs T -default 1
                    326: T script method_callback
                    327: 
                    328: proc method_callback {method args} {
                    329:   if {$method == "xShmBarrier"} {
                    330:     incr ::barrier_count
                    331:     if {$::barrier_count == 2} {
                    332:       # This code is executed within the xShmBarrier() callback invoked
                    333:       # by the client running recovery as part of writing the recovered
                    334:       # wal-index header. If a second client attempts to access the 
                    335:       # database now, it reads a corrupt (partially written) wal-index
                    336:       # header. But it cannot even get that far, as the first client
                    337:       # is still holding all the locks (recovery takes an exclusive lock
                    338:       # on *all* db locks, preventing access by any other client).
                    339:       #
                    340:       # If global variable ::wal3_do_lockfailure is non-zero, then set
                    341:       # things up so that an IO error occurs within an xShmLock() callback
                    342:       # made by the second client (aka [db2]).
                    343:       #
                    344:       sqlite3 db2 test.db
                    345:       if { $::wal3_do_lockfailure } { T filter xShmLock }
                    346:       set ::testrc [ catch { db2 eval "SELECT * FROM t1" } ::testmsg ]
                    347:       T filter {}
                    348:       db2 close
                    349:     }
                    350:   }
                    351: 
                    352:   if {$method == "xShmLock"} {
                    353:     foreach {file handle spec} $args break
                    354:     if { $spec == "2 1 lock shared" } {
                    355:       return SQLITE_IOERR
                    356:     }
                    357:   }
                    358: 
                    359:   return SQLITE_OK
                    360: }
                    361: 
                    362: # Test a normal SQLITE_BUSY return.
                    363: #
                    364: T filter xShmBarrier
                    365: set testrc ""
                    366: set testmsg ""
                    367: set barrier_count 0
                    368: set wal3_do_lockfailure 0
                    369: do_test wal3-5.2 {
                    370:   faultsim_restore_and_reopen
                    371:   execsql { SELECT * FROM t1 }
                    372: } {1 2 3 4}
                    373: do_test wal3-5.3 {
                    374:   list $::testrc $::testmsg
                    375: } {1 {database is locked}}
                    376: db close
                    377: 
                    378: # Test an SQLITE_IOERR return.
                    379: #
                    380: T filter xShmBarrier
                    381: set barrier_count 0
                    382: set wal3_do_lockfailure 1
                    383: set testrc ""
                    384: set testmsg ""
                    385: do_test wal3-5.4 {
                    386:   faultsim_restore_and_reopen
                    387:   execsql { SELECT * FROM t1 }
                    388: } {1 2 3 4}
                    389: do_test wal3-5.5 {
                    390:   list $::testrc $::testmsg
                    391: } {1 {disk I/O error}}
                    392: 
                    393: db close
                    394: T delete
                    395: 
                    396: #-------------------------------------------------------------------------
                    397: # When opening a read-transaction on a database, if the entire log has
                    398: # already been copied to the database file, the reader grabs a special
                    399: # kind of read lock (on aReadMark[0]). This set of test cases tests the 
                    400: # outcome of the following:
                    401: #
                    402: #   + The reader discovering that between the time when it determined 
                    403: #     that the log had been completely backfilled and the lock is obtained
                    404: #     that a writer has written to the log. In this case the reader should
                    405: #     acquire a different read-lock (not aReadMark[0]) and read the new
                    406: #     snapshot.
                    407: #
                    408: #   + The attempt to obtain the lock on aReadMark[0] fails with SQLITE_BUSY.
                    409: #     This can happen if a checkpoint is ongoing. In this case also simply
                    410: #     obtain a different read-lock.
                    411: #
                    412: catch {db close}
                    413: testvfs T -default 1
                    414: do_test wal3-6.1.1 {
                    415:   forcedelete test.db test.db-journal test.db wal
                    416:   sqlite3 db test.db
                    417:   execsql { PRAGMA auto_vacuum = off }
                    418:   execsql { PRAGMA journal_mode = WAL }
                    419:   execsql {
                    420:     CREATE TABLE t1(a, b);
                    421:     INSERT INTO t1 VALUES('o', 't');
                    422:     INSERT INTO t1 VALUES('t', 'f');
                    423:   }
                    424: } {}
                    425: do_test wal3-6.1.2 {
                    426:   sqlite3 db2 test.db
                    427:   sqlite3 db3 test.db
                    428:   execsql { BEGIN ; SELECT * FROM t1 } db3
                    429: } {o t t f}
                    430: do_test wal3-6.1.3 {
                    431:   execsql { PRAGMA wal_checkpoint } db2
                    432: } {0 4 4}
                    433: 
                    434: # At this point the log file has been fully checkpointed. However, 
                    435: # connection [db3] holds a lock that prevents the log from being wrapped.
                    436: # Test case 3.6.1.4 has [db] attempt a read-lock on aReadMark[0]. But
                    437: # as it is obtaining the lock, [db2] appends to the log file.
                    438: #
                    439: T filter xShmLock
                    440: T script lock_callback
                    441: proc lock_callback {method file handle spec} {
                    442:   if {$spec == "3 1 lock shared"} {
                    443:     # This is the callback for [db] to obtain the read lock on aReadMark[0].
                    444:     # Disable future callbacks using [T filter {}] and write to the log
                    445:     # file using [db2]. [db3] is preventing [db2] from wrapping the log
                    446:     # here, so this is an append.
                    447:     T filter {}
                    448:     db2 eval { INSERT INTO t1 VALUES('f', 's') }
                    449:   }
                    450:   return SQLITE_OK
                    451: }
                    452: do_test wal3-6.1.4 {
                    453:   execsql {
                    454:     BEGIN;
                    455:     SELECT * FROM t1;
                    456:   }
                    457: } {o t t f f s}
                    458: 
                    459: # [db] should be left holding a read-lock on some slot other than 
                    460: # aReadMark[0]. Test this by demonstrating that the read-lock is preventing
                    461: # the log from being wrapped.
                    462: #
                    463: do_test wal3-6.1.5 {
                    464:   db3 eval COMMIT
                    465:   db2 eval { PRAGMA wal_checkpoint }
                    466:   set sz1 [file size test.db-wal]
                    467:   db2 eval { INSERT INTO t1 VALUES('s', 'e') }
                    468:   set sz2 [file size test.db-wal]
                    469:   expr {$sz2>$sz1}
                    470: } {1}
                    471: 
                    472: # Test that if [db2] had not interfered when [db] was trying to grab
                    473: # aReadMark[0], it would have been possible to wrap the log in 3.6.1.5.
                    474: #
                    475: do_test wal3-6.1.6 {
                    476:   execsql { COMMIT }
                    477:   execsql { PRAGMA wal_checkpoint } db2
                    478:   execsql {
                    479:     BEGIN;
                    480:     SELECT * FROM t1;
                    481:   }
                    482: } {o t t f f s s e}
                    483: do_test wal3-6.1.7 {
                    484:   db2 eval { PRAGMA wal_checkpoint }
                    485:   set sz1 [file size test.db-wal]
                    486:   db2 eval { INSERT INTO t1 VALUES('n', 't') }
                    487:   set sz2 [file size test.db-wal]
                    488:   expr {$sz2==$sz1}
                    489: } {1}
                    490: 
                    491: db3 close
                    492: db2 close
                    493: db close
                    494: 
                    495: do_test wal3-6.2.1 {
                    496:   forcedelete test.db test.db-journal test.db wal
                    497:   sqlite3 db test.db
                    498:   sqlite3 db2 test.db
                    499:   execsql { PRAGMA auto_vacuum = off }
                    500:   execsql { PRAGMA journal_mode = WAL }
                    501:   execsql {
                    502:     CREATE TABLE t1(a, b);
                    503:     INSERT INTO t1 VALUES('h', 'h');
                    504:     INSERT INTO t1 VALUES('l', 'b');
                    505:   }
                    506: } {}
                    507: 
                    508: T filter xShmLock
                    509: T script lock_callback
                    510: proc lock_callback {method file handle spec} {
                    511:   if {$spec == "3 1 unlock exclusive"} {
                    512:     T filter {}
                    513:     set ::R [db2 eval {
                    514:       BEGIN;
                    515:       SELECT * FROM t1;
                    516:     }]
                    517:   }
                    518: }
                    519: do_test wal3-6.2.2 {
                    520:   execsql { PRAGMA wal_checkpoint }
                    521: } {0 4 4}
                    522: do_test wal3-6.2.3 {
                    523:   set ::R
                    524: } {h h l b}
                    525: do_test wal3-6.2.4 {
                    526:   set sz1 [file size test.db-wal]
                    527:   execsql { INSERT INTO t1 VALUES('b', 'c'); }
                    528:   set sz2 [file size test.db-wal]
                    529:   expr {$sz2 > $sz1}
                    530: } {1}
                    531: do_test wal3-6.2.5 {
                    532:   db2 eval { COMMIT }
                    533:   execsql { PRAGMA wal_checkpoint }
                    534:   set sz1 [file size test.db-wal]
                    535:   execsql { INSERT INTO t1 VALUES('n', 'o'); }
                    536:   set sz2 [file size test.db-wal]
                    537:   expr {$sz2 == $sz1}
                    538: } {1}
                    539:  
                    540: db2 close
                    541: db close
                    542: T delete
                    543: 
                    544: #-------------------------------------------------------------------------
                    545: # When opening a read-transaction on a database, if the entire log has
                    546: # not yet been copied to the database file, the reader grabs a read
                    547: # lock on aReadMark[x], where x>0. The following test cases experiment
                    548: # with the outcome of the following:
                    549: #
                    550: #   + The reader discovering that between the time when it read the
                    551: #     wal-index header and the lock was obtained that a writer has 
                    552: #     written to the log. In this case the reader should re-read the 
                    553: #     wal-index header and lock a snapshot corresponding to the new 
                    554: #     header.
                    555: #
                    556: #   + The value in the aReadMark[x] slot has been modified since it was
                    557: #     read.
                    558: #
                    559: catch {db close}
                    560: testvfs T -default 1
                    561: do_test wal3-7.1.1 {
                    562:   forcedelete test.db test.db-journal test.db wal
                    563:   sqlite3 db test.db
                    564:   execsql {
                    565:     PRAGMA journal_mode = WAL;
                    566:     CREATE TABLE blue(red PRIMARY KEY, green);
                    567:   }
                    568: } {wal}
                    569: 
                    570: T script method_callback
                    571: T filter xOpen
                    572: proc method_callback {method args} {
                    573:   if {$method == "xOpen"} { return "reader" }
                    574: }
                    575: do_test wal3-7.1.2 {
                    576:   sqlite3 db2 test.db
                    577:   execsql { SELECT * FROM blue } db2
                    578: } {}
                    579: 
                    580: T filter xShmLock
                    581: set ::locks [list]
                    582: proc method_callback {method file handle spec} {
                    583:   if {$handle != "reader" } { return }
                    584:   if {$method == "xShmLock"} {
                    585:     catch { execsql { INSERT INTO blue VALUES(1, 2) } }
                    586:     catch { execsql { INSERT INTO blue VALUES(3, 4) } }
                    587:   }
                    588:   lappend ::locks $spec
                    589: }
                    590: do_test wal3-7.1.3 {
                    591:   execsql { SELECT * FROM blue } db2
                    592: } {1 2 3 4}
                    593: do_test wal3-7.1.4 {
                    594:   set ::locks
                    595: } {{4 1 lock shared} {4 1 unlock shared} {5 1 lock shared} {5 1 unlock shared}}
                    596: 
                    597: set ::locks [list]
                    598: proc method_callback {method file handle spec} {
                    599:   if {$handle != "reader" } { return }
                    600:   if {$method == "xShmLock"} {
                    601:     catch { execsql { INSERT INTO blue VALUES(5, 6) } }
                    602:   }
                    603:   lappend ::locks $spec
                    604: }
                    605: do_test wal3-7.2.1 {
                    606:   execsql { SELECT * FROM blue } db2
                    607: } {1 2 3 4 5 6}
                    608: do_test wal3-7.2.2 {
                    609:   set ::locks
                    610: } {{5 1 lock shared} {5 1 unlock shared} {4 1 lock shared} {4 1 unlock shared}}
                    611: 
                    612: db close
                    613: db2 close
                    614: T delete
                    615: 
                    616: #-------------------------------------------------------------------------
                    617: # 
                    618: do_test wal3-8.1 {
                    619:   forcedelete test.db test.db-journal test.db wal
                    620:   sqlite3 db test.db
                    621:   sqlite3 db2 test.db
                    622:   execsql {
                    623:     PRAGMA auto_vacuum = off;
                    624:     PRAGMA journal_mode = WAL;
                    625:     CREATE TABLE b(c);
                    626:     INSERT INTO b VALUES('Tehran');
                    627:     INSERT INTO b VALUES('Qom');
                    628:     INSERT INTO b VALUES('Markazi');
                    629:     PRAGMA wal_checkpoint;
                    630:   }
                    631: } {wal 0 5 5}
                    632: do_test wal3-8.2 {
                    633:   execsql { SELECT * FROM b }
                    634: } {Tehran Qom Markazi}
                    635: do_test wal3-8.3 {
                    636:   db eval { SELECT * FROM b } {
                    637:     db eval { INSERT INTO b VALUES('Qazvin') }
                    638:     set r [db2 eval { SELECT * FROM b }]
                    639:     break
                    640:   }
                    641:   set r
                    642: } {Tehran Qom Markazi Qazvin}
                    643: do_test wal3-8.4 {
                    644:   execsql {
                    645:     INSERT INTO b VALUES('Gilan');
                    646:     INSERT INTO b VALUES('Ardabil');
                    647:   }
                    648: } {}
                    649: db2 close
                    650: 
                    651: faultsim_save_and_close
                    652: testvfs T -default 1
                    653: faultsim_restore_and_reopen
                    654: T filter xShmLock
                    655: T script lock_callback
                    656: 
                    657: proc lock_callback {method file handle spec} {
                    658:   if {$spec == "4 1 unlock exclusive"} {
                    659:     T filter {}
                    660:     set ::r [catchsql { SELECT * FROM b } db2]
                    661:   }
                    662: }
                    663: sqlite3 db test.db
                    664: sqlite3 db2 test.db
                    665: do_test wal3-8.5 {
                    666:   execsql { SELECT * FROM b }
                    667: } {Tehran Qom Markazi Qazvin Gilan Ardabil}
                    668: do_test wal3-8.6 {
                    669:   set ::r
                    670: } {1 {locking protocol}}
                    671: 
                    672: db close
                    673: db2 close
                    674: 
                    675: faultsim_restore_and_reopen
                    676: sqlite3 db2 test.db
                    677: T filter xShmLock
                    678: T script lock_callback
                    679: proc lock_callback {method file handle spec} {
                    680:   if {$spec == "1 7 unlock exclusive"} {
                    681:     T filter {}
                    682:     set ::r [catchsql { SELECT * FROM b } db2]
                    683:   }
                    684: }
                    685: unset ::r
                    686: do_test wal3-8.5 {
                    687:   execsql { SELECT * FROM b }
                    688: } {Tehran Qom Markazi Qazvin Gilan Ardabil}
                    689: do_test wal3-8.6 {
                    690:   set ::r
                    691: } {1 {locking protocol}}
                    692: 
                    693: db close
                    694: db2 close
                    695: T delete
                    696: 
                    697: #-------------------------------------------------------------------------
                    698: # When a connection opens a read-lock on the database, it searches for
                    699: # an aReadMark[] slot that is already set to the mxFrame value for the
                    700: # new transaction. If it cannot find one, it attempts to obtain an 
                    701: # exclusive lock on an aReadMark[] slot for the purposes of modifying
                    702: # the value, then drops back to a shared-lock for the duration of the
                    703: # transaction.
                    704: #
                    705: # This test case verifies that if an exclusive lock cannot be obtained
                    706: # on any aReadMark[] slot (because there are already several readers),
                    707: # the client takes a shared-lock on a slot without modifying the value
                    708: # and continues.
                    709: #
                    710: set nConn 50
                    711: if { [string match *BSD $tcl_platform(os)] } { set nConn 25 }
                    712: do_test wal3-9.0 {
                    713:   forcedelete test.db test.db-journal test.db wal
                    714:   sqlite3 db test.db
                    715:   execsql {
                    716:     PRAGMA page_size = 1024;
                    717:     PRAGMA journal_mode = WAL;
                    718:     CREATE TABLE whoami(x);
                    719:     INSERT INTO whoami VALUES('nobody');
                    720:   }
                    721: } {wal}
                    722: for {set i 0} {$i < $nConn} {incr i} {
                    723:   set c db$i
                    724:   do_test wal3-9.1.$i {
                    725:     sqlite3 $c test.db
                    726:     execsql { UPDATE whoami SET x = $c }
                    727:     execsql {
                    728:       BEGIN;
                    729:       SELECT * FROM whoami
                    730:     } $c
                    731:   } $c
                    732: }
                    733: for {set i 0} {$i < $nConn} {incr i} {
                    734:   set c db$i
                    735:   do_test wal3-9.2.$i {
                    736:     execsql { SELECT * FROM whoami } $c
                    737:   } $c
                    738: }
                    739: 
                    740: set sz [expr 1024 * (2+$AUTOVACUUM)]
                    741: do_test wal3-9.3 {
                    742:   for {set i 0} {$i < ($nConn-1)} {incr i} { db$i close }
                    743:   execsql { PRAGMA wal_checkpoint } 
                    744:   byte_is_zero test.db [expr $sz-1024]
                    745: } {1}
                    746: do_test wal3-9.4 {
                    747:   db[expr $nConn-1] close
                    748:   execsql { PRAGMA wal_checkpoint } 
                    749:   set sz2 [file size test.db]
                    750:   byte_is_zero test.db [expr $sz-1024]
                    751: } {0}
                    752: 
                    753: do_multiclient_test tn {
                    754:   do_test wal3-10.$tn.1 {
                    755:     sql1 {
                    756:       PRAGMA page_size = 1024;
                    757:       CREATE TABLE t1(x);
                    758:       PRAGMA journal_mode = WAL;
                    759:       PRAGMA wal_autocheckpoint = 100000;
                    760:       BEGIN;
                    761:         INSERT INTO t1 VALUES(randomblob(800));
                    762:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 2
                    763:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 4
                    764:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 8
                    765:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 16
                    766:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 32
                    767:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 64
                    768:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 128
                    769:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 256
                    770:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 512
                    771:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 1024
                    772:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 2048
                    773:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 4096
                    774:         INSERT INTO t1 SELECT randomblob(800) FROM t1;   -- 8192
                    775:       COMMIT;
                    776:       CREATE INDEX i1 ON t1(x);
                    777:     }
                    778: 
                    779:     expr {[file size test.db-wal] > [expr 1032*9000]}
                    780:   } 1
                    781: 
                    782:   do_test wal3-10.$tn.2 {
                    783:     sql2 {PRAGMA integrity_check}
                    784:   } {ok}
                    785: }
                    786: 
                    787: finish_test

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