151d2d036Sdanielk1977# 2007 September 10 251d2d036Sdanielk1977# 351d2d036Sdanielk1977# The author disclaims copyright to this source code. In place of 451d2d036Sdanielk1977# a legal notice, here is a blessing: 551d2d036Sdanielk1977# 651d2d036Sdanielk1977# May you do good and not evil. 751d2d036Sdanielk1977# May you find forgiveness for yourself and forgive others. 851d2d036Sdanielk1977# May you share freely, never taking more than you give. 951d2d036Sdanielk1977# 1051d2d036Sdanielk1977#*********************************************************************** 1151d2d036Sdanielk1977# 1251d2d036Sdanielk1977# This file contains tests that attempt to break the pcache module 1351d2d036Sdanielk1977# by bombarding it with simultaneous requests from multiple threads. 1451d2d036Sdanielk1977# 156d961009Sdanielk1977# $Id: thread003.test,v 1.8 2009/03/26 14:48:07 danielk1977 Exp $ 1651d2d036Sdanielk1977 1751d2d036Sdanielk1977set testdir [file dirname $argv0] 1851d2d036Sdanielk1977 1951d2d036Sdanielk1977source $testdir/tester.tcl 206d961009Sdanielk1977if {[run_thread_tests]==0} { finish_test ; return } 2151d2d036Sdanielk1977 2251d2d036Sdanielk1977# Set up a couple of different databases full of pseudo-randomly 2351d2d036Sdanielk1977# generated data. 2451d2d036Sdanielk1977# 2551d2d036Sdanielk1977do_test thread003.1.1 { 2651d2d036Sdanielk1977 execsql { 2751d2d036Sdanielk1977 BEGIN; 2851d2d036Sdanielk1977 CREATE TABLE t1(a, b, c); 2951d2d036Sdanielk1977 } 3051d2d036Sdanielk1977 for {set ii 0} {$ii < 5000} {incr ii} { 3151d2d036Sdanielk1977 execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))} 3251d2d036Sdanielk1977 } 3351d2d036Sdanielk1977 execsql { 3451d2d036Sdanielk1977 CREATE INDEX i1 ON t1(a, b); 3551d2d036Sdanielk1977 COMMIT; 3651d2d036Sdanielk1977 } 3751d2d036Sdanielk1977} {} 3851d2d036Sdanielk1977do_test thread003.1.2 { 3951d2d036Sdanielk1977 expr {([file size test.db] / 1024) > 2000} 4051d2d036Sdanielk1977} {1} 4151d2d036Sdanielk1977do_test thread003.1.3 { 4251d2d036Sdanielk1977 db close 43fda06befSmistachkin forcedelete test2.db 4451d2d036Sdanielk1977 sqlite3 db test2.db 4551d2d036Sdanielk1977} {} 4651d2d036Sdanielk1977do_test thread003.1.4 { 4751d2d036Sdanielk1977 execsql { 4851d2d036Sdanielk1977 BEGIN; 4951d2d036Sdanielk1977 CREATE TABLE t1(a, b, c); 5051d2d036Sdanielk1977 } 5151d2d036Sdanielk1977 for {set ii 0} {$ii < 5000} {incr ii} { 5251d2d036Sdanielk1977 execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))} 5351d2d036Sdanielk1977 } 5451d2d036Sdanielk1977 execsql { 5551d2d036Sdanielk1977 CREATE INDEX i1 ON t1(a, b); 5651d2d036Sdanielk1977 COMMIT; 5751d2d036Sdanielk1977 } 5851d2d036Sdanielk1977} {} 5951d2d036Sdanielk1977do_test thread003.1.5 { 6051d2d036Sdanielk1977 expr {([file size test.db] / 1024) > 2000} 6151d2d036Sdanielk1977} {1} 6251d2d036Sdanielk1977do_test thread003.1.6 { 6351d2d036Sdanielk1977 db close 6451d2d036Sdanielk1977} {} 6551d2d036Sdanielk1977 6651d2d036Sdanielk1977 6751d2d036Sdanielk1977# This test opens a connection on each of the large (>2MB) database files 6851d2d036Sdanielk1977# created by the previous block. The connections do not share a cache. 6951d2d036Sdanielk1977# Both "cache_size" parameters are set to 15, so there is a maximum of 7051d2d036Sdanielk1977# 30 pages available globally. 7151d2d036Sdanielk1977# 7251d2d036Sdanielk1977# Then, in separate threads, the databases are randomly queried over and 7351d2d036Sdanielk1977# over again. This will force the connections to recycle clean pages from 7451d2d036Sdanielk1977# each other. If there is a thread-safety problem, a segfault or assertion 7551d2d036Sdanielk1977# failure may eventually occur. 7651d2d036Sdanielk1977# 7751d2d036Sdanielk1977set nSecond 30 7851d2d036Sdanielk1977puts "Starting thread003.2 (should run for ~$nSecond seconds)" 7951d2d036Sdanielk1977do_test thread003.2 { 8051d2d036Sdanielk1977 foreach zFile {test.db test2.db} { 8151d2d036Sdanielk1977 set SCRIPT [format { 8281fa193aSdanielk1977 set iEnd [expr {[clock_seconds] + %d}] 83*0ee469c9Sdrh set ::DB [sqlthread open %s xyzzy] 8451d2d036Sdanielk1977 8551d2d036Sdanielk1977 # Set the cache size to 15 pages per cache. 30 available globally. 8651d2d036Sdanielk1977 execsql { PRAGMA cache_size = 15 } 8751d2d036Sdanielk1977 8881fa193aSdanielk1977 while {[clock_seconds] < $iEnd} { 8951d2d036Sdanielk1977 set iQuery [expr {int(rand()*5000)}] 9051d2d036Sdanielk1977 execsql " SELECT * FROM t1 WHERE a = $iQuery " 9151d2d036Sdanielk1977 } 9251d2d036Sdanielk1977 9351d2d036Sdanielk1977 sqlite3_close $::DB 9451d2d036Sdanielk1977 expr 1 9551d2d036Sdanielk1977 } $nSecond $zFile] 9651d2d036Sdanielk1977 9751d2d036Sdanielk1977 unset -nocomplain finished($zFile) 9851d2d036Sdanielk1977 thread_spawn finished($zFile) $thread_procs $SCRIPT 9951d2d036Sdanielk1977 } 10051d2d036Sdanielk1977 foreach zFile {test.db test2.db} { 10151d2d036Sdanielk1977 if {![info exists finished($zFile)]} { 10251d2d036Sdanielk1977 vwait finished($zFile) 10351d2d036Sdanielk1977 } 10451d2d036Sdanielk1977 } 10551d2d036Sdanielk1977 expr 0 10651d2d036Sdanielk1977} {0} 10751d2d036Sdanielk1977 108f599a199Sdanielk1977# This test is the same as the test above, except that each thread also 109f599a199Sdanielk1977# writes to the database. This causes pages to be moved back and forth 110f599a199Sdanielk1977# between the caches internal dirty and clean lists, which is another 111f599a199Sdanielk1977# opportunity for a thread-related bug to present itself. 112f599a199Sdanielk1977# 113f599a199Sdanielk1977set nSecond 30 114f599a199Sdanielk1977puts "Starting thread003.3 (should run for ~$nSecond seconds)" 115f599a199Sdanielk1977do_test thread003.3 { 116f599a199Sdanielk1977 foreach zFile {test.db test2.db} { 117f599a199Sdanielk1977 set SCRIPT [format { 11881fa193aSdanielk1977 set iStart [clock_seconds] 11981fa193aSdanielk1977 set iEnd [expr {[clock_seconds] + %d}] 120*0ee469c9Sdrh set ::DB [sqlthread open %s xyzzy] 121f599a199Sdanielk1977 122f599a199Sdanielk1977 # Set the cache size to 15 pages per cache. 30 available globally. 123f599a199Sdanielk1977 execsql { PRAGMA cache_size = 15 } 124f599a199Sdanielk1977 12581fa193aSdanielk1977 while {[clock_seconds] < $iEnd} { 126f599a199Sdanielk1977 set iQuery [expr {int(rand()*5000)}] 127f599a199Sdanielk1977 execsql "SELECT * FROM t1 WHERE a = $iQuery" 128f599a199Sdanielk1977 execsql "UPDATE t1 SET b = randomblob(200) 129f599a199Sdanielk1977 WHERE a < $iQuery AND a > $iQuery + 20 130f599a199Sdanielk1977 " 131f599a199Sdanielk1977 } 132f599a199Sdanielk1977 133f599a199Sdanielk1977 sqlite3_close $::DB 134f599a199Sdanielk1977 expr 1 135f599a199Sdanielk1977 } $nSecond $zFile] 136f599a199Sdanielk1977 137f599a199Sdanielk1977 unset -nocomplain finished($zFile) 138f599a199Sdanielk1977 thread_spawn finished($zFile) $thread_procs $SCRIPT 139f599a199Sdanielk1977 } 140f599a199Sdanielk1977 foreach zFile {test.db test2.db} { 141f599a199Sdanielk1977 if {![info exists finished($zFile)]} { 142f599a199Sdanielk1977 vwait finished($zFile) 143f599a199Sdanielk1977 } 144f599a199Sdanielk1977 } 145f599a199Sdanielk1977 expr 0 146f599a199Sdanielk1977} {0} 147f599a199Sdanielk1977 148f599a199Sdanielk1977# In this test case, one thread is continually querying the database. 149f599a199Sdanielk1977# The other thread does not have a database connection, but calls 150f599a199Sdanielk1977# sqlite3_release_memory() over and over again. 151f599a199Sdanielk1977# 152f599a199Sdanielk1977set nSecond 30 15320736d82Sdanielk1977puts "Starting thread003.4 (should run for ~$nSecond seconds)" 1543dbb0572Sdanielk1977unset -nocomplain finished(1) 1553dbb0572Sdanielk1977unset -nocomplain finished(2) 156f599a199Sdanielk1977do_test thread003.4 { 157f599a199Sdanielk1977 thread_spawn finished(1) $thread_procs [format { 15881fa193aSdanielk1977 set iEnd [expr {[clock_seconds] + %d}] 159*0ee469c9Sdrh set ::DB [sqlthread open test.db xyzzy] 160f599a199Sdanielk1977 161f599a199Sdanielk1977 # Set the cache size to 15 pages per cache. 30 available globally. 162f599a199Sdanielk1977 execsql { PRAGMA cache_size = 15 } 163f599a199Sdanielk1977 16481fa193aSdanielk1977 while {[clock_seconds] < $iEnd} { 165f599a199Sdanielk1977 set iQuery [expr {int(rand()*5000)}] 166f599a199Sdanielk1977 execsql "SELECT * FROM t1 WHERE a = $iQuery" 167f599a199Sdanielk1977 } 168f599a199Sdanielk1977 169f599a199Sdanielk1977 sqlite3_close $::DB 170f599a199Sdanielk1977 expr 1 171f599a199Sdanielk1977 } $nSecond] 172f599a199Sdanielk1977 thread_spawn finished(2) [format { 17381fa193aSdanielk1977 set iEnd [expr {[clock_seconds] + %d}] 174f599a199Sdanielk1977 17581fa193aSdanielk1977 while {[clock_seconds] < $iEnd} { 176f599a199Sdanielk1977 sqlite3_release_memory 1000 177f599a199Sdanielk1977 } 178f599a199Sdanielk1977 } $nSecond] 179f599a199Sdanielk1977 180f599a199Sdanielk1977 foreach ii {1 2} { 181f599a199Sdanielk1977 if {![info exists finished($ii)]} { 182f599a199Sdanielk1977 vwait finished($ii) 183f599a199Sdanielk1977 } 184f599a199Sdanielk1977 } 185f599a199Sdanielk1977 expr 0 186f599a199Sdanielk1977} {0} 187f599a199Sdanielk1977 188a32e0d05Sdrhset sqlite_open_file_count 0 18951d2d036Sdanielk1977finish_test 190