summaryrefslogtreecommitdiffstats
path: root/test/busy2.test
diff options
context:
space:
mode:
Diffstat (limited to 'test/busy2.test')
-rw-r--r--test/busy2.test171
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