xref: /sqlite-3.40.0/test/busy2.test (revision c59b7b1f)
1# 2020 June 30
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 test the busy handler
12#
13
14
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17source $testdir/lock_common.tcl
18set testprefix busy2
19
20do_multiclient_test tn {
21  do_test 1.$tn.0 {
22    sql2 {
23      CREATE TABLE t1(a, b);
24      PRAGMA journal_mode = wal;
25      INSERT INTO t1 VALUES('A', 'B');
26    }
27  } {wal}
28
29  do_test 1.$tn.1 {
30    code1 { db timeout 1000 }
31    sql1 { SELECT * FROM t1 }
32  } {A B}
33
34  do_test 1.$tn.2 {
35    sql2 {
36      BEGIN;
37        INSERT INTO t1 VALUES('C', 'D');
38    }
39  } {}
40
41  do_test 1.$tn.3 {
42    set us [lindex [time { catch { sql1 { BEGIN EXCLUSIVE } } }] 0]
43    expr {$us>950000 && $us<1500000}
44  } {1}
45
46  do_test 1.$tn.4 {
47    sql2 {
48      COMMIT
49    }
50  } {}
51}
52
53#-------------------------------------------------------------------------
54
55do_multiclient_test tn {
56  # Make the db a WAL mode db. And add a table and a row to it. Then open
57  # a second connection within process 1. Process 1 now has connections
58  # [db] and [db1.2], process 2 has connection [db2] only.
59  #
60  # Configure all connections to use a 1000 ms timeout.
61  #
62  do_test 2.$tn.0 {
63    code1 {
64      sqlite3 db1.2 test.db
65    }
66    sql1 {
67      PRAGMA auto_vacuum = off;
68      PRAGMA journal_mode = wal;
69      CREATE TABLE t1(a, b);
70      INSERT INTO t1 VALUES(1, 2);
71    }
72    code2 {
73      db2 timeout 1000
74    }
75    code1 {
76      db1.2 timeout 1000
77      db    timeout 1000
78      db1.2 eval {SELECT * FROM t1}
79    }
80  } {1 2}
81
82  # Take a read lock with [db] in process 1.
83  #
84  do_test 2.$tn.1 {
85    sql1 {
86      BEGIN;
87        SELECT * FROM t1;
88    }
89  } {1 2}
90
91  # Insert a row using [db2] in process 2. Then try a passive checkpoint.
92  # It fails to checkpoint the final frame (due to the readlock taken by
93  # [db]), and returns in less than 250ms.
94  do_test 2.$tn.2 {
95    sql2 { INSERT INTO t1 VALUES(3, 4) }
96    set us [lindex [time {
97      set res [code2 { db2 eval { PRAGMA wal_checkpoint } }]
98    }] 0]
99    list [expr $us < 250000] $res
100  } {1 {0 4 3}}
101
102  # Now try a FULL checkpoint with [db2]. It returns SQLITE_BUSY. And takes
103  # over 950ms to do so.
104  do_test 2.$tn.3 {
105    set us [lindex [time {
106      set res [code2 { db2 eval { PRAGMA wal_checkpoint = FULL } }]
107    }] 0]
108    list [expr $us > 950000] $res
109  } {1 {1 4 3}}
110
111  # Passive checkpoint with [db1.2] (process 1). No SQLITE_BUSY, returns
112  # in under 250ms.
113  do_test 2.$tn.4 {
114    set us [lindex [time {
115      set res [code1 { db1.2 eval { PRAGMA wal_checkpoint } }]
116    }] 0]
117    list [expr $us < 250000] $res
118  } {1 {0 4 3}}
119
120  # Full checkpoint with [db1.2] (process 1). SQLITE_BUSY returned in
121  # a bit over 950ms.
122  do_test 2.$tn.5 {
123    set us [lindex [time {
124      set res [code1 { db1.2 eval { PRAGMA wal_checkpoint = FULL } }]
125    }] 0]
126    list [expr $us > 950000] $res
127  } {1 {1 4 3}}
128
129  code1 {
130    db1.2 close
131  }
132}
133
134#-------------------------------------------------------------------------
135# Check that even if the busy-handler fails (returns zero) within a
136# call to sqlite3_prepare() (or _v2(), or _v3()), it is still invoked
137# the next time an SQLITE_BUSY is encountered.
138#
139do_multiclient_test tn {
140  code1 {
141    set ::busy_called 0
142    proc busy {args} {
143      if {$::busy_called} { return 1 }
144      set ::busy_called 1
145      return 0
146    }
147    db busy busy
148  }
149
150  do_test 3.$tn.1 {
151    sql2 {
152      CREATE TABLE t1(x);
153      BEGIN EXCLUSIVE;
154        INSERT INTO t1 VALUES('x');
155    }
156  } {}
157
158  do_test 3.$tn.2 {
159    set ::busy_called 0
160    list [catch { sql1 { SELECT * FROM t1 } } msg] $::busy_called
161  } {1 1}
162
163  do_test 3.$tn.3 {
164    set ::busy_called 0
165    list [catch { sql1 { SELECT * FROM t1 } } msg] $::busy_called
166  } {1 1}
167
168}
169
170finish_test
171