github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/busy2.test (about) 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 15 set testdir [file dirname $argv0] 16 source $testdir/tester.tcl 17 source $testdir/lock_common.tcl 18 set testprefix busy2 19 20 do_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 55 do_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 # 139 do_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 170 finish_test