1# 2007 September 10 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# 12# This file contains tests that attempt to break the pcache module 13# by bombarding it with simultaneous requests from multiple threads. 14# 15# $Id: thread003.test,v 1.2 2008/08/28 10:21:17 danielk1977 Exp $ 16 17set testdir [file dirname $argv0] 18 19source $testdir/tester.tcl 20source $testdir/thread_common.tcl 21if {[info commands sqlthread] eq ""} { 22 finish_test 23 return 24} 25 26# Set up a couple of different databases full of pseudo-randomly 27# generated data. 28# 29do_test thread003.1.1 { 30 execsql { 31 BEGIN; 32 CREATE TABLE t1(a, b, c); 33 } 34 for {set ii 0} {$ii < 5000} {incr ii} { 35 execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))} 36 } 37 execsql { 38 CREATE INDEX i1 ON t1(a, b); 39 COMMIT; 40 } 41} {} 42do_test thread003.1.2 { 43 expr {([file size test.db] / 1024) > 2000} 44} {1} 45do_test thread003.1.3 { 46 db close 47 file delete -force test2.db 48 sqlite3 db test2.db 49} {} 50do_test thread003.1.4 { 51 execsql { 52 BEGIN; 53 CREATE TABLE t1(a, b, c); 54 } 55 for {set ii 0} {$ii < 5000} {incr ii} { 56 execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))} 57 } 58 execsql { 59 CREATE INDEX i1 ON t1(a, b); 60 COMMIT; 61 } 62} {} 63do_test thread003.1.5 { 64 expr {([file size test.db] / 1024) > 2000} 65} {1} 66do_test thread003.1.6 { 67 db close 68} {} 69 70 71# This test opens a connection on each of the large (>2MB) database files 72# created by the previous block. The connections do not share a cache. 73# Both "cache_size" parameters are set to 15, so there is a maximum of 74# 30 pages available globally. 75# 76# Then, in separate threads, the databases are randomly queried over and 77# over again. This will force the connections to recycle clean pages from 78# each other. If there is a thread-safety problem, a segfault or assertion 79# failure may eventually occur. 80# 81set nSecond 30 82puts "Starting thread003.2 (should run for ~$nSecond seconds)" 83do_test thread003.2 { 84 foreach zFile {test.db test2.db} { 85 set SCRIPT [format { 86 set iStart [clock seconds] 87 set iEnd [expr {[clock seconds] + %d}] 88 set ::DB [sqlthread open %s] 89 90 # Set the cache size to 15 pages per cache. 30 available globally. 91 execsql { PRAGMA cache_size = 15 } 92 93 while {[clock seconds] < $iEnd} { 94 set iQuery [expr {int(rand()*5000)}] 95 execsql " SELECT * FROM t1 WHERE a = $iQuery " 96 } 97 98 sqlite3_close $::DB 99 expr 1 100 } $nSecond $zFile] 101 102 unset -nocomplain finished($zFile) 103 thread_spawn finished($zFile) $thread_procs $SCRIPT 104 } 105 foreach zFile {test.db test2.db} { 106 if {![info exists finished($zFile)]} { 107 vwait finished($zFile) 108 } 109 } 110 expr 0 111} {0} 112 113# This test is the same as the test above, except that each thread also 114# writes to the database. This causes pages to be moved back and forth 115# between the caches internal dirty and clean lists, which is another 116# opportunity for a thread-related bug to present itself. 117# 118set nSecond 30 119puts "Starting thread003.3 (should run for ~$nSecond seconds)" 120do_test thread003.3 { 121 foreach zFile {test.db test2.db} { 122 set SCRIPT [format { 123 set iStart [clock seconds] 124 set iEnd [expr {[clock seconds] + %d}] 125 set ::DB [sqlthread open %s] 126 127 # Set the cache size to 15 pages per cache. 30 available globally. 128 execsql { PRAGMA cache_size = 15 } 129 130 while {[clock seconds] < $iEnd} { 131 set iQuery [expr {int(rand()*5000)}] 132 execsql "SELECT * FROM t1 WHERE a = $iQuery" 133 execsql "UPDATE t1 SET b = randomblob(200) 134 WHERE a < $iQuery AND a > $iQuery + 20 135 " 136 } 137 138 sqlite3_close $::DB 139 expr 1 140 } $nSecond $zFile] 141 142 unset -nocomplain finished($zFile) 143 thread_spawn finished($zFile) $thread_procs $SCRIPT 144 } 145 foreach zFile {test.db test2.db} { 146 if {![info exists finished($zFile)]} { 147 vwait finished($zFile) 148 } 149 } 150 expr 0 151} {0} 152 153# In this test case, one thread is continually querying the database. 154# The other thread does not have a database connection, but calls 155# sqlite3_release_memory() over and over again. 156# 157set nSecond 30 158puts "Starting thread003.3 (should run for ~$nSecond seconds)" 159do_test thread003.4 { 160 thread_spawn finished(1) $thread_procs [format { 161 set iEnd [expr {[clock seconds] + %d}] 162 set ::DB [sqlthread open test.db] 163 164 # Set the cache size to 15 pages per cache. 30 available globally. 165 execsql { PRAGMA cache_size = 15 } 166 167 while {[clock seconds] < $iEnd} { 168 set iQuery [expr {int(rand()*5000)}] 169 execsql "SELECT * FROM t1 WHERE a = $iQuery" 170 } 171 172 sqlite3_close $::DB 173 expr 1 174 } $nSecond] 175 thread_spawn finished(2) [format { 176 set iEnd [expr {[clock seconds] + %d}] 177 178 while {[clock seconds] < $iEnd} { 179 sqlite3_release_memory 1000 180 } 181 } $nSecond] 182 183 foreach ii {1 2} { 184 if {![info exists finished($ii)]} { 185 vwait finished($ii) 186 } 187 } 188 expr 0 189} {0} 190 191finish_test 192 193 194