thread003.test 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. set testdir [file dirname $argv0]
  17. source $testdir/tester.tcl
  18. if {[run_thread_tests]==0} { finish_test ; return }
  19. # Set up a couple of different databases full of pseudo-randomly
  20. # generated data.
  21. #
  22. do_test thread003.1.1 {
  23. execsql {
  24. BEGIN;
  25. CREATE TABLE t1(a, b, c);
  26. }
  27. for {set ii 0} {$ii < 5000} {incr ii} {
  28. execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
  29. }
  30. execsql {
  31. CREATE INDEX i1 ON t1(a, b);
  32. COMMIT;
  33. }
  34. } {}
  35. do_test thread003.1.2 {
  36. expr {([file size test.db] / 1024) > 2000}
  37. } {1}
  38. do_test thread003.1.3 {
  39. db close
  40. forcedelete test2.db
  41. sqlite3 db test2.db
  42. } {}
  43. do_test thread003.1.4 {
  44. execsql {
  45. BEGIN;
  46. CREATE TABLE t1(a, b, c);
  47. }
  48. for {set ii 0} {$ii < 5000} {incr ii} {
  49. execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
  50. }
  51. execsql {
  52. CREATE INDEX i1 ON t1(a, b);
  53. COMMIT;
  54. }
  55. } {}
  56. do_test thread003.1.5 {
  57. expr {([file size test.db] / 1024) > 2000}
  58. } {1}
  59. do_test thread003.1.6 {
  60. db close
  61. } {}
  62. # This test opens a connection on each of the large (>2MB) database files
  63. # created by the previous block. The connections do not share a cache.
  64. # Both "cache_size" parameters are set to 15, so there is a maximum of
  65. # 30 pages available globally.
  66. #
  67. # Then, in separate threads, the databases are randomly queried over and
  68. # over again. This will force the connections to recycle clean pages from
  69. # each other. If there is a thread-safety problem, a segfault or assertion
  70. # failure may eventually occur.
  71. #
  72. set nSecond 30
  73. puts "Starting thread003.2 (should run for ~$nSecond seconds)"
  74. do_test thread003.2 {
  75. foreach zFile {test.db test2.db} {
  76. set SCRIPT [format {
  77. set iEnd [expr {[clock_seconds] + %d}]
  78. set ::DB [sqlthread open %s xyzzy]
  79. # Set the cache size to 15 pages per cache. 30 available globally.
  80. execsql { PRAGMA cache_size = 15 }
  81. while {[clock_seconds] < $iEnd} {
  82. set iQuery [expr {int(rand()*5000)}]
  83. execsql " SELECT * FROM t1 WHERE a = $iQuery "
  84. }
  85. sqlite3_close $::DB
  86. expr 1
  87. } $nSecond $zFile]
  88. unset -nocomplain finished($zFile)
  89. thread_spawn finished($zFile) $thread_procs $SCRIPT
  90. }
  91. foreach zFile {test.db test2.db} {
  92. if {![info exists finished($zFile)]} {
  93. vwait finished($zFile)
  94. }
  95. }
  96. expr 0
  97. } {0}
  98. # This test is the same as the test above, except that each thread also
  99. # writes to the database. This causes pages to be moved back and forth
  100. # between the caches internal dirty and clean lists, which is another
  101. # opportunity for a thread-related bug to present itself.
  102. #
  103. set nSecond 30
  104. puts "Starting thread003.3 (should run for ~$nSecond seconds)"
  105. do_test thread003.3 {
  106. foreach zFile {test.db test2.db} {
  107. set SCRIPT [format {
  108. set iStart [clock_seconds]
  109. set iEnd [expr {[clock_seconds] + %d}]
  110. set ::DB [sqlthread open %s xyzzy]
  111. # Set the cache size to 15 pages per cache. 30 available globally.
  112. execsql { PRAGMA cache_size = 15 }
  113. while {[clock_seconds] < $iEnd} {
  114. set iQuery [expr {int(rand()*5000)}]
  115. execsql "SELECT * FROM t1 WHERE a = $iQuery"
  116. execsql "UPDATE t1 SET b = randomblob(200)
  117. WHERE a < $iQuery AND a > $iQuery + 20
  118. "
  119. }
  120. sqlite3_close $::DB
  121. expr 1
  122. } $nSecond $zFile]
  123. unset -nocomplain finished($zFile)
  124. thread_spawn finished($zFile) $thread_procs $SCRIPT
  125. }
  126. foreach zFile {test.db test2.db} {
  127. if {![info exists finished($zFile)]} {
  128. vwait finished($zFile)
  129. }
  130. }
  131. expr 0
  132. } {0}
  133. # In this test case, one thread is continually querying the database.
  134. # The other thread does not have a database connection, but calls
  135. # sqlite3_release_memory() over and over again.
  136. #
  137. set nSecond 30
  138. puts "Starting thread003.4 (should run for ~$nSecond seconds)"
  139. unset -nocomplain finished(1)
  140. unset -nocomplain finished(2)
  141. do_test thread003.4 {
  142. thread_spawn finished(1) $thread_procs [format {
  143. set iEnd [expr {[clock_seconds] + %d}]
  144. set ::DB [sqlthread open test.db xyzzy]
  145. # Set the cache size to 15 pages per cache. 30 available globally.
  146. execsql { PRAGMA cache_size = 15 }
  147. while {[clock_seconds] < $iEnd} {
  148. set iQuery [expr {int(rand()*5000)}]
  149. execsql "SELECT * FROM t1 WHERE a = $iQuery"
  150. }
  151. sqlite3_close $::DB
  152. expr 1
  153. } $nSecond]
  154. thread_spawn finished(2) [format {
  155. set iEnd [expr {[clock_seconds] + %d}]
  156. while {[clock_seconds] < $iEnd} {
  157. sqlite3_release_memory 1000
  158. }
  159. } $nSecond]
  160. foreach ii {1 2} {
  161. if {![info exists finished($ii)]} {
  162. vwait finished($ii)
  163. }
  164. }
  165. expr 0
  166. } {0}
  167. set sqlite_open_file_count 0
  168. finish_test