| # 2020 May 06 |
| # |
| # The author disclaims copyright to this source code. In place of |
| # a legal notice, here is a blessing: |
| # |
| # May you do good and not evil. |
| # May you find forgiveness for yourself and forgive others. |
| # May you share freely, never taking more than you give. |
| # |
| #*********************************************************************** |
| # |
| # TESTRUNNER: slow |
| # |
| |
| set testdir [file dirname $argv0] |
| source $testdir/tester.tcl |
| source $testdir/lock_common.tcl |
| set testprefix walsetlk |
| |
| ifcapable !wal {finish_test ; return } |
| db timeout 1000 |
| |
| #------------------------------------------------------------------------- |
| # 1.*: Test that nothing goes wrong if recovery is forced while opening |
| # a write transaction or performing a checkpoint with blocking locks. |
| # |
| |
| do_execsql_test 1.0 { |
| CREATE TABLE t1(x, y); |
| PRAGMA journal_mode = wal; |
| INSERT INTO t1 VALUES(1, 2); |
| INSERT INTO t1 VALUES(3, 4); |
| INSERT INTO t1 VALUES(5, 6); |
| INSERT INTO t1 VALUES(7, 8); |
| } {wal} |
| |
| sqlite3 db2 test.db |
| db2 timeout 1000 |
| |
| do_execsql_test -db db2 1.1 { |
| SELECT * FROM t1 |
| } {1 2 3 4 5 6 7 8} |
| |
| set fd [open test.db-shm r+] |
| puts $fd "blahblahblahblah" |
| flush $fd |
| |
| do_execsql_test 1.2 { |
| BEGIN; |
| INSERT INTO t1 VALUES(9, 10); |
| } |
| |
| do_execsql_test -db db2 1.3 { |
| SELECT * FROM t1 |
| } {1 2 3 4 5 6 7 8} |
| |
| do_test 1.4 { |
| list [catch {db2 eval { BEGIN EXCLUSIVE }} msg] $msg |
| } {1 {database is locked}} |
| |
| do_execsql_test 1.5 { COMMIT } |
| do_execsql_test -db db2 1.6 { |
| SELECT * FROM t1 |
| } {1 2 3 4 5 6 7 8 9 10} |
| |
| puts $fd "blahblahblahblah" |
| flush $fd |
| |
| do_execsql_test -db db2 1.7 { |
| PRAGMA wal_checkpoint = TRUNCATE |
| } {0 0 0} |
| |
| do_test 1.8 { |
| file size test.db-wal |
| } 0 |
| |
| close $fd |
| db close |
| db2 close |
| #------------------------------------------------------------------------- |
| |
| do_multiclient_test tn { |
| |
| testvfs tvfs -fullshm 1 |
| db close |
| sqlite3 db test.db -vfs tvfs |
| tvfs script xSleep_callback |
| tvfs filter xSleep |
| |
| set ::sleep_count 0 |
| proc xSleep_callback {xSleep nMs} { |
| after [expr $nMs / 1000] |
| incr ::sleep_count |
| } |
| |
| do_test 2.$tn.1 { |
| sql1 { |
| PRAGMA journal_mode = wal; |
| CREATE TABLE t1(s, v); |
| INSERT INTO t1 VALUES(1, 2); |
| INSERT INTO t1 VALUES(3, 4); |
| INSERT INTO t1 VALUES(5, 6); |
| } |
| code1 { db timeout 1100 } |
| } {} |
| |
| do_test 2.$tn.2 { |
| sql2 { |
| BEGIN; |
| INSERT INTO t1 VALUES(7, 8); |
| } |
| } {} |
| |
| do_test 2.$tn.3 { |
| set us [lindex [time { catch {db eval "BEGIN EXCLUSIVE"} }] 0] |
| expr $us>1000000 && $us<4000000 |
| } {1} |
| |
| do_test 2.$tn.4 { |
| sql2 { COMMIT } |
| sql1 { SELECT * FROM t1 } |
| } {1 2 3 4 5 6 7 8} |
| |
| do_test 2.$tn.5 { |
| sql2 { |
| BEGIN; |
| INSERT INTO t1 VALUES(9, 10); |
| } |
| } {} |
| |
| do_test 2.$tn.6 { |
| set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] |
| expr $us>1000000 && $us<4000000 |
| } {1} |
| |
| do_test 2.$tn.7 { |
| sql2 { |
| COMMIT; |
| BEGIN; |
| SELECT * FROM t1; |
| } |
| } {1 2 3 4 5 6 7 8 9 10} |
| |
| do_test 2.$tn.8 { |
| set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] |
| expr $us>1000000 && $us<4000000 |
| } {1} |
| do_test 2.$tn.9 { |
| sql3 { |
| INSERT INTO t1 VALUES(11, 12); |
| } |
| sql2 { |
| COMMIT; |
| BEGIN; |
| SELECT * FROM t1; |
| } |
| sql3 { |
| INSERT INTO t1 VALUES(13, 14); |
| } |
| } {} |
| |
| do_test 2.$tn.10 { |
| set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] |
| expr $us>1000000 && $us<4000000 |
| } {1} |
| |
| do_test 2.$tn.11 { |
| sql3 { |
| BEGIN; |
| SELECT * FROM t1; |
| } |
| sql1 { INSERT INTO t1 VALUES(15, 16); } |
| } {} |
| |
| do_test 2.$tn.12 { |
| set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] |
| expr $us>1000000 && $us<4000000 |
| } {1} |
| |
| do_test 2.$tn.13 { |
| sql2 { |
| COMMIT; |
| BEGIN; |
| SELECT * FROM t1; |
| } |
| sql1 { INSERT INTO t1 VALUES(17, 18); } |
| } {} |
| |
| do_test 2.$tn.14 { |
| set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] |
| expr $us>1000000 && $us<4000000 |
| } {1} |
| |
| db close |
| tvfs delete |
| |
| # Set bSleep to true if it is expected that the above used xSleep() to |
| # wait for locks. bSleep is true unless SQLITE_ENABLE_SETLK_TIMEOUT is |
| # set to 1 and either: |
| # |
| # * the OS is windows, or |
| # * the OS is unix and the tests were run with each connection |
| # in a separate process. |
| # |
| set bSleep 1 |
| if {$::sqlite_options(setlk_timeout)==1} { |
| if {$::tcl_platform(platform) eq "windows"} { |
| set bSleep 0 |
| } |
| if {$::tcl_platform(platform) eq "unix"} { |
| set bSleep [expr $tn==2] |
| } |
| } |
| |
| do_test 2.$tn.15.$bSleep { |
| expr $::sleep_count > 0 |
| } $bSleep |
| } |
| |
| #------------------------------------------------------------------------- |
| reset_db |
| |
| testvfs tvfs -fullshm 1 |
| tvfs script xSleep_callback |
| tvfs filter xSleep |
| |
| set ::sleep_count 0 |
| proc xSleep_callback {xSleep nMs} { |
| after [expr $nMs / 1000] |
| incr ::sleep_count |
| breakpoint |
| } |
| |
| sqlite3 db2 test.db -vfs tvfs |
| db2 timeout 1000 |
| |
| do_execsql_test 3.0 { |
| PRAGMA journal_mode = wal; |
| CREATE TABLE x1(x, y); |
| BEGIN; |
| INSERT INTO x1 VALUES(1, 2); |
| } {wal} |
| |
| do_execsql_test -db db2 3.1a { |
| SELECT * FROM x1 |
| } {} |
| |
| do_test 3.1b { |
| list [catch { db2 eval {BEGIN EXCLUSIVE} } msg] $msg |
| } {1 {database is locked}} |
| |
| # Set bExpect to true if calls to xSleep() are expected. Such calls are |
| # expected unless this is an SQLITE_ENABLE_SETLK_TIMEOUT=1 build. |
| set bExpect 1 |
| if {$tcl_platform(platform) eq "windows" && $::sqlite_options(setlk_timeout)==1} { |
| set bExpect 0 |
| } |
| do_test 3.2 { |
| expr {$::sleep_count > 0} |
| } $bExpect |
| set ::sleep_count 0 |
| |
| do_execsql_test 3.3 { |
| COMMIT; |
| } |
| |
| # Launch a non-blocking testfixture process to write-lock the |
| # database for 2000 ms. |
| testfixture_nb done { |
| sqlite3 db test.db |
| db eval { |
| BEGIN EXCLUSIVE; |
| INSERT INTO x1 VALUES(3, 4); |
| } |
| after 2000 |
| db eval { |
| COMMIT |
| } |
| } |
| |
| after 500 {set ok 1} |
| vwait ok |
| |
| db2 timeout 5000 |
| do_test 3.4 { |
| set t [lindex [time { db2 eval { BEGIN EXCLUSIVE } }] 0] |
| expr ($t>1000000) |
| } {1} |
| |
| # Set bExpect to true if calls to xSleep() are expected. Such calls are |
| # expected unless this is an SQLITE_ENABLE_SETLK_TIMEOUT=1 build. |
| set bExpect 1 |
| if {$::sqlite_options(setlk_timeout)==1} { |
| set bExpect 0 |
| } |
| do_test 3.5 { |
| expr {$::sleep_count > 0} |
| } $bExpect |
| |
| do_execsql_test -db db2 3.6 { |
| INSERT INTO x1 VALUES(5, 6); |
| COMMIT; |
| SELECT * FROM x1; |
| } {1 2 3 4 5 6} |
| |
| # Launch a non-blocking testfixture process to write-lock the |
| # database for 2000 ms. |
| testfixture_nb done { |
| sqlite3 db test.db |
| db eval { |
| BEGIN EXCLUSIVE; |
| INSERT INTO x1 VALUES(7, 8); |
| } |
| after 2000 |
| db eval { |
| COMMIT |
| } |
| db close |
| } |
| |
| after 500 {set ok 1} |
| vwait ok |
| |
| db2 timeout 0x7FFFFFFF |
| do_test 3.7 { |
| set t [lindex [time { db2 eval { BEGIN EXCLUSIVE } }] 0] |
| expr ($t>1000000) |
| } {1} |
| |
| # Set bExpect to true if calls to xSleep() are expected. Such calls are |
| # expected unless this is an SQLITE_ENABLE_SETLK_TIMEOUT=1 build. |
| set bExpect 1 |
| if {$::sqlite_options(setlk_timeout)==1} { |
| set bExpect 0 |
| } |
| do_test 3.8 { |
| expr {$::sleep_count > 0} |
| } $bExpect |
| |
| do_execsql_test -db db2 3.9 { |
| INSERT INTO x1 VALUES(9, 10); |
| COMMIT; |
| SELECT * FROM x1; |
| } {1 2 3 4 5 6 7 8 9 10} |
| |
| db2 close |
| tvfs delete |
| |
| finish_test |
| |