blob: 61fb8496a82bea43dc72b9301a9c6ae1b9f925f2 [file] [log] [blame]
# 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
#
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