xref: /sqlite-3.40.0/test/thread003.test (revision 81fa193a)
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