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.1.1.1 2012/02/21 17:04:16 misho 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: forcedelete 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 xyzzy]
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 xyzzy]
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 xyzzy]
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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>