xref: /sqlite-3.40.0/test/thread003.test (revision f599a199)
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.2 2008/08/28 10:21:17 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 iStart [clock seconds]
87      set iEnd [expr {[clock seconds] + %d}]
88      set ::DB [sqlthread open %s]
89
90      # Set the cache size to 15 pages per cache. 30 available globally.
91      execsql { PRAGMA cache_size = 15 }
92
93      while {[clock seconds] < $iEnd} {
94        set iQuery [expr {int(rand()*5000)}]
95        execsql " SELECT * FROM t1 WHERE a = $iQuery "
96      }
97
98      sqlite3_close $::DB
99      expr 1
100    } $nSecond $zFile]
101
102    unset -nocomplain finished($zFile)
103    thread_spawn finished($zFile) $thread_procs $SCRIPT
104  }
105  foreach zFile {test.db test2.db} {
106    if {![info exists finished($zFile)]} {
107      vwait finished($zFile)
108    }
109  }
110  expr 0
111} {0}
112
113# This test is the same as the test above, except that each thread also
114# writes to the database. This causes pages to be moved back and forth
115# between the caches internal dirty and clean lists, which is another
116# opportunity for a thread-related bug to present itself.
117#
118set nSecond 30
119puts "Starting thread003.3 (should run for ~$nSecond seconds)"
120do_test thread003.3 {
121  foreach zFile {test.db test2.db} {
122    set SCRIPT [format {
123      set iStart [clock seconds]
124      set iEnd [expr {[clock seconds] + %d}]
125      set ::DB [sqlthread open %s]
126
127      # Set the cache size to 15 pages per cache. 30 available globally.
128      execsql { PRAGMA cache_size = 15 }
129
130      while {[clock seconds] < $iEnd} {
131        set iQuery [expr {int(rand()*5000)}]
132        execsql "SELECT * FROM t1 WHERE a = $iQuery"
133        execsql "UPDATE t1 SET b = randomblob(200)
134                 WHERE a < $iQuery AND a > $iQuery + 20
135        "
136      }
137
138      sqlite3_close $::DB
139      expr 1
140    } $nSecond $zFile]
141
142    unset -nocomplain finished($zFile)
143    thread_spawn finished($zFile) $thread_procs $SCRIPT
144  }
145  foreach zFile {test.db test2.db} {
146    if {![info exists finished($zFile)]} {
147      vwait finished($zFile)
148    }
149  }
150  expr 0
151} {0}
152
153# In this test case, one thread is continually querying the database.
154# The other thread does not have a database connection, but calls
155# sqlite3_release_memory() over and over again.
156#
157set nSecond 30
158puts "Starting thread003.3 (should run for ~$nSecond seconds)"
159do_test thread003.4 {
160  thread_spawn finished(1) $thread_procs [format {
161    set iEnd [expr {[clock seconds] + %d}]
162    set ::DB [sqlthread open test.db]
163
164    # Set the cache size to 15 pages per cache. 30 available globally.
165    execsql { PRAGMA cache_size = 15 }
166
167    while {[clock seconds] < $iEnd} {
168      set iQuery [expr {int(rand()*5000)}]
169      execsql "SELECT * FROM t1 WHERE a = $iQuery"
170    }
171
172    sqlite3_close $::DB
173    expr 1
174  } $nSecond]
175  thread_spawn finished(2) [format {
176    set iEnd [expr {[clock seconds] + %d}]
177
178    while {[clock seconds] < $iEnd} {
179      sqlite3_release_memory 1000
180    }
181  } $nSecond]
182
183  foreach ii {1 2} {
184    if {![info exists finished($ii)]} {
185      vwait finished($ii)
186    }
187  }
188  expr 0
189} {0}
190
191finish_test
192
193
194