• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17set testdir [file dirname $argv0]
18
19source $testdir/tester.tcl
20if {[run_thread_tests]==0} { finish_test ; return }
21
22# Set up a couple of different databases full of pseudo-randomly
23# generated data.
24#
25do_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} {}
38do_test thread003.1.2 {
39  expr {([file size test.db] / 1024) > 2000}
40} {1}
41do_test thread003.1.3 {
42  db close
43  file delete -force test2.db
44  sqlite3 db test2.db
45} {}
46do_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} {}
59do_test thread003.1.5 {
60  expr {([file size test.db] / 1024) > 2000}
61} {1}
62do_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#
77set nSecond 30
78puts "Starting thread003.2 (should run for ~$nSecond seconds)"
79do_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#
113set nSecond 30
114puts "Starting thread003.3 (should run for ~$nSecond seconds)"
115do_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#
152set nSecond 30
153puts "Starting thread003.4 (should run for ~$nSecond seconds)"
154unset -nocomplain finished(1)
155unset -nocomplain finished(2)
156do_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
188set sqlite_open_file_count 0
189finish_test
190