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.3 2008/08/28 13:55:10 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 iEnd [expr {[clock_seconds] + %d}] 87 set ::DB [sqlthread open %s] 88 89 # Set the cache size to 15 pages per cache. 30 available globally. 90 execsql { PRAGMA cache_size = 15 } 91 92 while {[clock_seconds] < $iEnd} { 93 set iQuery [expr {int(rand()*5000)}] 94 execsql " SELECT * FROM t1 WHERE a = $iQuery " 95 } 96 97 sqlite3_close $::DB 98 expr 1 99 } $nSecond $zFile] 100 101 unset -nocomplain finished($zFile) 102 thread_spawn finished($zFile) $thread_procs $SCRIPT 103 } 104 foreach zFile {test.db test2.db} { 105 if {![info exists finished($zFile)]} { 106 vwait finished($zFile) 107 } 108 } 109 expr 0 110} {0} 111 112# This test is the same as the test above, except that each thread also 113# writes to the database. This causes pages to be moved back and forth 114# between the caches internal dirty and clean lists, which is another 115# opportunity for a thread-related bug to present itself. 116# 117set nSecond 30 118puts "Starting thread003.3 (should run for ~$nSecond seconds)" 119do_test thread003.3 { 120 foreach zFile {test.db test2.db} { 121 set SCRIPT [format { 122 set iStart [clock_seconds] 123 set iEnd [expr {[clock_seconds] + %d}] 124 set ::DB [sqlthread open %s] 125 126 # Set the cache size to 15 pages per cache. 30 available globally. 127 execsql { PRAGMA cache_size = 15 } 128 129 while {[clock_seconds] < $iEnd} { 130 set iQuery [expr {int(rand()*5000)}] 131 execsql "SELECT * FROM t1 WHERE a = $iQuery" 132 execsql "UPDATE t1 SET b = randomblob(200) 133 WHERE a < $iQuery AND a > $iQuery + 20 134 " 135 } 136 137 sqlite3_close $::DB 138 expr 1 139 } $nSecond $zFile] 140 141 unset -nocomplain finished($zFile) 142 thread_spawn finished($zFile) $thread_procs $SCRIPT 143 } 144 foreach zFile {test.db test2.db} { 145 if {![info exists finished($zFile)]} { 146 vwait finished($zFile) 147 } 148 } 149 expr 0 150} {0} 151 152# In this test case, one thread is continually querying the database. 153# The other thread does not have a database connection, but calls 154# sqlite3_release_memory() over and over again. 155# 156set nSecond 30 157puts "Starting thread003.3 (should run for ~$nSecond seconds)" 158do_test thread003.4 { 159 thread_spawn finished(1) $thread_procs [format { 160 set iEnd [expr {[clock_seconds] + %d}] 161 set ::DB [sqlthread open test.db] 162 163 # Set the cache size to 15 pages per cache. 30 available globally. 164 execsql { PRAGMA cache_size = 15 } 165 166 while {[clock_seconds] < $iEnd} { 167 set iQuery [expr {int(rand()*5000)}] 168 execsql "SELECT * FROM t1 WHERE a = $iQuery" 169 } 170 171 sqlite3_close $::DB 172 expr 1 173 } $nSecond] 174 thread_spawn finished(2) [format { 175 set iEnd [expr {[clock_seconds] + %d}] 176 177 while {[clock_seconds] < $iEnd} { 178 sqlite3_release_memory 1000 179 } 180 } $nSecond] 181 182 foreach ii {1 2} { 183 if {![info exists finished($ii)]} { 184 vwait finished($ii) 185 } 186 } 187 expr 0 188} {0} 189 190finish_test 191 192 193