xref: /sqlite-3.40.0/test/thread003.test (revision 0ee469c9)
151d2d036Sdanielk1977# 2007 September 10
251d2d036Sdanielk1977#
351d2d036Sdanielk1977# The author disclaims copyright to this source code.  In place of
451d2d036Sdanielk1977# a legal notice, here is a blessing:
551d2d036Sdanielk1977#
651d2d036Sdanielk1977#    May you do good and not evil.
751d2d036Sdanielk1977#    May you find forgiveness for yourself and forgive others.
851d2d036Sdanielk1977#    May you share freely, never taking more than you give.
951d2d036Sdanielk1977#
1051d2d036Sdanielk1977#***********************************************************************
1151d2d036Sdanielk1977#
1251d2d036Sdanielk1977#   This file contains tests that attempt to break the pcache module
1351d2d036Sdanielk1977#   by bombarding it with simultaneous requests from multiple threads.
1451d2d036Sdanielk1977#
156d961009Sdanielk1977# $Id: thread003.test,v 1.8 2009/03/26 14:48:07 danielk1977 Exp $
1651d2d036Sdanielk1977
1751d2d036Sdanielk1977set testdir [file dirname $argv0]
1851d2d036Sdanielk1977
1951d2d036Sdanielk1977source $testdir/tester.tcl
206d961009Sdanielk1977if {[run_thread_tests]==0} { finish_test ; return }
2151d2d036Sdanielk1977
2251d2d036Sdanielk1977# Set up a couple of different databases full of pseudo-randomly
2351d2d036Sdanielk1977# generated data.
2451d2d036Sdanielk1977#
2551d2d036Sdanielk1977do_test thread003.1.1 {
2651d2d036Sdanielk1977  execsql {
2751d2d036Sdanielk1977    BEGIN;
2851d2d036Sdanielk1977    CREATE TABLE t1(a, b, c);
2951d2d036Sdanielk1977  }
3051d2d036Sdanielk1977  for {set ii 0} {$ii < 5000} {incr ii} {
3151d2d036Sdanielk1977    execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
3251d2d036Sdanielk1977  }
3351d2d036Sdanielk1977  execsql {
3451d2d036Sdanielk1977    CREATE INDEX i1 ON t1(a, b);
3551d2d036Sdanielk1977    COMMIT;
3651d2d036Sdanielk1977  }
3751d2d036Sdanielk1977} {}
3851d2d036Sdanielk1977do_test thread003.1.2 {
3951d2d036Sdanielk1977  expr {([file size test.db] / 1024) > 2000}
4051d2d036Sdanielk1977} {1}
4151d2d036Sdanielk1977do_test thread003.1.3 {
4251d2d036Sdanielk1977  db close
43fda06befSmistachkin  forcedelete test2.db
4451d2d036Sdanielk1977  sqlite3 db test2.db
4551d2d036Sdanielk1977} {}
4651d2d036Sdanielk1977do_test thread003.1.4 {
4751d2d036Sdanielk1977  execsql {
4851d2d036Sdanielk1977    BEGIN;
4951d2d036Sdanielk1977    CREATE TABLE t1(a, b, c);
5051d2d036Sdanielk1977  }
5151d2d036Sdanielk1977  for {set ii 0} {$ii < 5000} {incr ii} {
5251d2d036Sdanielk1977    execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
5351d2d036Sdanielk1977  }
5451d2d036Sdanielk1977  execsql {
5551d2d036Sdanielk1977    CREATE INDEX i1 ON t1(a, b);
5651d2d036Sdanielk1977    COMMIT;
5751d2d036Sdanielk1977  }
5851d2d036Sdanielk1977} {}
5951d2d036Sdanielk1977do_test thread003.1.5 {
6051d2d036Sdanielk1977  expr {([file size test.db] / 1024) > 2000}
6151d2d036Sdanielk1977} {1}
6251d2d036Sdanielk1977do_test thread003.1.6 {
6351d2d036Sdanielk1977  db close
6451d2d036Sdanielk1977} {}
6551d2d036Sdanielk1977
6651d2d036Sdanielk1977
6751d2d036Sdanielk1977# This test opens a connection on each of the large (>2MB) database files
6851d2d036Sdanielk1977# created by the previous block. The connections do not share a cache.
6951d2d036Sdanielk1977# Both "cache_size" parameters are set to 15, so there is a maximum of
7051d2d036Sdanielk1977# 30 pages available globally.
7151d2d036Sdanielk1977#
7251d2d036Sdanielk1977# Then, in separate threads, the databases are randomly queried over and
7351d2d036Sdanielk1977# over again. This will force the connections to recycle clean pages from
7451d2d036Sdanielk1977# each other. If there is a thread-safety problem, a segfault or assertion
7551d2d036Sdanielk1977# failure may eventually occur.
7651d2d036Sdanielk1977#
7751d2d036Sdanielk1977set nSecond 30
7851d2d036Sdanielk1977puts "Starting thread003.2 (should run for ~$nSecond seconds)"
7951d2d036Sdanielk1977do_test thread003.2 {
8051d2d036Sdanielk1977  foreach zFile {test.db test2.db} {
8151d2d036Sdanielk1977    set SCRIPT [format {
8281fa193aSdanielk1977      set iEnd [expr {[clock_seconds] + %d}]
83*0ee469c9Sdrh      set ::DB [sqlthread open %s xyzzy]
8451d2d036Sdanielk1977
8551d2d036Sdanielk1977      # Set the cache size to 15 pages per cache. 30 available globally.
8651d2d036Sdanielk1977      execsql { PRAGMA cache_size = 15 }
8751d2d036Sdanielk1977
8881fa193aSdanielk1977      while {[clock_seconds] < $iEnd} {
8951d2d036Sdanielk1977        set iQuery [expr {int(rand()*5000)}]
9051d2d036Sdanielk1977        execsql " SELECT * FROM t1 WHERE a = $iQuery "
9151d2d036Sdanielk1977      }
9251d2d036Sdanielk1977
9351d2d036Sdanielk1977      sqlite3_close $::DB
9451d2d036Sdanielk1977      expr 1
9551d2d036Sdanielk1977    } $nSecond $zFile]
9651d2d036Sdanielk1977
9751d2d036Sdanielk1977    unset -nocomplain finished($zFile)
9851d2d036Sdanielk1977    thread_spawn finished($zFile) $thread_procs $SCRIPT
9951d2d036Sdanielk1977  }
10051d2d036Sdanielk1977  foreach zFile {test.db test2.db} {
10151d2d036Sdanielk1977    if {![info exists finished($zFile)]} {
10251d2d036Sdanielk1977      vwait finished($zFile)
10351d2d036Sdanielk1977    }
10451d2d036Sdanielk1977  }
10551d2d036Sdanielk1977  expr 0
10651d2d036Sdanielk1977} {0}
10751d2d036Sdanielk1977
108f599a199Sdanielk1977# This test is the same as the test above, except that each thread also
109f599a199Sdanielk1977# writes to the database. This causes pages to be moved back and forth
110f599a199Sdanielk1977# between the caches internal dirty and clean lists, which is another
111f599a199Sdanielk1977# opportunity for a thread-related bug to present itself.
112f599a199Sdanielk1977#
113f599a199Sdanielk1977set nSecond 30
114f599a199Sdanielk1977puts "Starting thread003.3 (should run for ~$nSecond seconds)"
115f599a199Sdanielk1977do_test thread003.3 {
116f599a199Sdanielk1977  foreach zFile {test.db test2.db} {
117f599a199Sdanielk1977    set SCRIPT [format {
11881fa193aSdanielk1977      set iStart [clock_seconds]
11981fa193aSdanielk1977      set iEnd [expr {[clock_seconds] + %d}]
120*0ee469c9Sdrh      set ::DB [sqlthread open %s xyzzy]
121f599a199Sdanielk1977
122f599a199Sdanielk1977      # Set the cache size to 15 pages per cache. 30 available globally.
123f599a199Sdanielk1977      execsql { PRAGMA cache_size = 15 }
124f599a199Sdanielk1977
12581fa193aSdanielk1977      while {[clock_seconds] < $iEnd} {
126f599a199Sdanielk1977        set iQuery [expr {int(rand()*5000)}]
127f599a199Sdanielk1977        execsql "SELECT * FROM t1 WHERE a = $iQuery"
128f599a199Sdanielk1977        execsql "UPDATE t1 SET b = randomblob(200)
129f599a199Sdanielk1977                 WHERE a < $iQuery AND a > $iQuery + 20
130f599a199Sdanielk1977        "
131f599a199Sdanielk1977      }
132f599a199Sdanielk1977
133f599a199Sdanielk1977      sqlite3_close $::DB
134f599a199Sdanielk1977      expr 1
135f599a199Sdanielk1977    } $nSecond $zFile]
136f599a199Sdanielk1977
137f599a199Sdanielk1977    unset -nocomplain finished($zFile)
138f599a199Sdanielk1977    thread_spawn finished($zFile) $thread_procs $SCRIPT
139f599a199Sdanielk1977  }
140f599a199Sdanielk1977  foreach zFile {test.db test2.db} {
141f599a199Sdanielk1977    if {![info exists finished($zFile)]} {
142f599a199Sdanielk1977      vwait finished($zFile)
143f599a199Sdanielk1977    }
144f599a199Sdanielk1977  }
145f599a199Sdanielk1977  expr 0
146f599a199Sdanielk1977} {0}
147f599a199Sdanielk1977
148f599a199Sdanielk1977# In this test case, one thread is continually querying the database.
149f599a199Sdanielk1977# The other thread does not have a database connection, but calls
150f599a199Sdanielk1977# sqlite3_release_memory() over and over again.
151f599a199Sdanielk1977#
152f599a199Sdanielk1977set nSecond 30
15320736d82Sdanielk1977puts "Starting thread003.4 (should run for ~$nSecond seconds)"
1543dbb0572Sdanielk1977unset -nocomplain finished(1)
1553dbb0572Sdanielk1977unset -nocomplain finished(2)
156f599a199Sdanielk1977do_test thread003.4 {
157f599a199Sdanielk1977  thread_spawn finished(1) $thread_procs [format {
15881fa193aSdanielk1977    set iEnd [expr {[clock_seconds] + %d}]
159*0ee469c9Sdrh    set ::DB [sqlthread open test.db xyzzy]
160f599a199Sdanielk1977
161f599a199Sdanielk1977    # Set the cache size to 15 pages per cache. 30 available globally.
162f599a199Sdanielk1977    execsql { PRAGMA cache_size = 15 }
163f599a199Sdanielk1977
16481fa193aSdanielk1977    while {[clock_seconds] < $iEnd} {
165f599a199Sdanielk1977      set iQuery [expr {int(rand()*5000)}]
166f599a199Sdanielk1977      execsql "SELECT * FROM t1 WHERE a = $iQuery"
167f599a199Sdanielk1977    }
168f599a199Sdanielk1977
169f599a199Sdanielk1977    sqlite3_close $::DB
170f599a199Sdanielk1977    expr 1
171f599a199Sdanielk1977  } $nSecond]
172f599a199Sdanielk1977  thread_spawn finished(2) [format {
17381fa193aSdanielk1977    set iEnd [expr {[clock_seconds] + %d}]
174f599a199Sdanielk1977
17581fa193aSdanielk1977    while {[clock_seconds] < $iEnd} {
176f599a199Sdanielk1977      sqlite3_release_memory 1000
177f599a199Sdanielk1977    }
178f599a199Sdanielk1977  } $nSecond]
179f599a199Sdanielk1977
180f599a199Sdanielk1977  foreach ii {1 2} {
181f599a199Sdanielk1977    if {![info exists finished($ii)]} {
182f599a199Sdanielk1977      vwait finished($ii)
183f599a199Sdanielk1977    }
184f599a199Sdanielk1977  }
185f599a199Sdanielk1977  expr 0
186f599a199Sdanielk1977} {0}
187f599a199Sdanielk1977
188a32e0d05Sdrhset sqlite_open_file_count 0
18951d2d036Sdanielk1977finish_test
190