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