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