diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:28:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:28:19 +0000 |
commit | 18657a960e125336f704ea058e25c27bd3900dcb (patch) | |
tree | 17b438b680ed45a996d7b59951e6aa34023783f2 /test/busy2.test | |
parent | Initial commit. (diff) | |
download | sqlite3-18657a960e125336f704ea058e25c27bd3900dcb.tar.xz sqlite3-18657a960e125336f704ea058e25c27bd3900dcb.zip |
Adding upstream version 3.40.1.upstream/3.40.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/busy2.test')
-rw-r--r-- | test/busy2.test | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/test/busy2.test b/test/busy2.test new file mode 100644 index 0000000..ec420c8 --- /dev/null +++ b/test/busy2.test @@ -0,0 +1,171 @@ +# 2020 June 30 +# +# 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. +# +#*********************************************************************** +# This file test the busy handler +# +# TESTRUNNER: slow + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +set testprefix busy2 + +do_multiclient_test tn { + do_test 1.$tn.0 { + sql2 { + CREATE TABLE t1(a, b); + PRAGMA journal_mode = wal; + INSERT INTO t1 VALUES('A', 'B'); + } + } {wal} + + do_test 1.$tn.1 { + code1 { db timeout 1000 } + sql1 { SELECT * FROM t1 } + } {A B} + + do_test 1.$tn.2 { + sql2 { + BEGIN; + INSERT INTO t1 VALUES('C', 'D'); + } + } {} + + do_test 1.$tn.3 { + set us [lindex [time { catch { sql1 { BEGIN EXCLUSIVE } } }] 0] + expr {$us>950000 && $us<1500000} + } {1} + + do_test 1.$tn.4 { + sql2 { + COMMIT + } + } {} +} + +#------------------------------------------------------------------------- + +do_multiclient_test tn { + # Make the db a WAL mode db. And add a table and a row to it. Then open + # a second connection within process 1. Process 1 now has connections + # [db] and [db1.2], process 2 has connection [db2] only. + # + # Configure all connections to use a 1000 ms timeout. + # + do_test 2.$tn.0 { + code1 { + sqlite3 db1.2 test.db + } + sql1 { + PRAGMA auto_vacuum = off; + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } + code2 { + db2 timeout 1000 + } + code1 { + db1.2 timeout 1000 + db timeout 1000 + db1.2 eval {SELECT * FROM t1} + } + } {1 2} + + # Take a read lock with [db] in process 1. + # + do_test 2.$tn.1 { + sql1 { + BEGIN; + SELECT * FROM t1; + } + } {1 2} + + # Insert a row using [db2] in process 2. Then try a passive checkpoint. + # It fails to checkpoint the final frame (due to the readlock taken by + # [db]), and returns in less than 250ms. + do_test 2.$tn.2 { + sql2 { INSERT INTO t1 VALUES(3, 4) } + set us [lindex [time { + set res [code2 { db2 eval { PRAGMA wal_checkpoint } }] + }] 0] + list [expr $us < 250000] $res + } {1 {0 4 3}} + + # Now try a FULL checkpoint with [db2]. It returns SQLITE_BUSY. And takes + # over 950ms to do so. + do_test 2.$tn.3 { + set us [lindex [time { + set res [code2 { db2 eval { PRAGMA wal_checkpoint = FULL } }] + }] 0] + list [expr $us > 950000] $res + } {1 {1 4 3}} + + # Passive checkpoint with [db1.2] (process 1). No SQLITE_BUSY, returns + # in under 250ms. + do_test 2.$tn.4 { + set us [lindex [time { + set res [code1 { db1.2 eval { PRAGMA wal_checkpoint } }] + }] 0] + list [expr $us < 250000] $res + } {1 {0 4 3}} + + # Full checkpoint with [db1.2] (process 1). SQLITE_BUSY returned in + # a bit over 950ms. + do_test 2.$tn.5 { + set us [lindex [time { + set res [code1 { db1.2 eval { PRAGMA wal_checkpoint = FULL } }] + }] 0] + list [expr $us > 950000] $res + } {1 {1 4 3}} + + code1 { + db1.2 close + } +} + +#------------------------------------------------------------------------- +# Check that even if the busy-handler fails (returns zero) within a +# call to sqlite3_prepare() (or _v2(), or _v3()), it is still invoked +# the next time an SQLITE_BUSY is encountered. +# +do_multiclient_test tn { + code1 { + set ::busy_called 0 + proc busy {args} { + if {$::busy_called} { return 1 } + set ::busy_called 1 + return 0 + } + db busy busy + } + + do_test 3.$tn.1 { + sql2 { + CREATE TABLE t1(x); + BEGIN EXCLUSIVE; + INSERT INTO t1 VALUES('x'); + } + } {} + + do_test 3.$tn.2 { + set ::busy_called 0 + list [catch { sql1 { SELECT * FROM t1 } } msg] $::busy_called + } {1 1} + + do_test 3.$tn.3 { + set ::busy_called 0 + list [catch { sql1 { SELECT * FROM t1 } } msg] $::busy_called + } {1 1} + +} + +finish_test |