Index: third_party/sqlite/sqlite-src-3080704/test/walthread.test |
diff --git a/third_party/sqlite/sqlite-src-3080704/test/walthread.test b/third_party/sqlite/sqlite-src-3080704/test/walthread.test |
deleted file mode 100644 |
index 6249ce11af09cd131813283d5ab12e6a83f08bdd..0000000000000000000000000000000000000000 |
--- a/third_party/sqlite/sqlite-src-3080704/test/walthread.test |
+++ /dev/null |
@@ -1,527 +0,0 @@ |
-# 2010 April 13 |
-# |
-# The author disclaims copyright to this source code. In place of |
-# a legal notice, here is a blessing: |
-# |
-# May you do good and not evil. |
-# May you find forgiveness for yourself and forgive others. |
-# May you share freely, never taking more than you give. |
-# |
-#*********************************************************************** |
-# This file implements regression tests for SQLite library. The |
-# focus of this file is testing the operation of the library in |
-# "PRAGMA journal_mode=WAL" mode with multiple threads. |
-# |
- |
-set testdir [file dirname $argv0] |
- |
-source $testdir/tester.tcl |
-source $testdir/lock_common.tcl |
-if {[run_thread_tests]==0} { finish_test ; return } |
-ifcapable !wal { finish_test ; return } |
- |
-set sqlite_walsummary_mmap_incr 64 |
- |
-# How long, in seconds, to run each test for. If a test is set to run for |
-# 0 seconds, it is omitted entirely. |
-# |
-unset -nocomplain seconds |
-set seconds(walthread-1) 20 |
-set seconds(walthread-2) 20 |
-set seconds(walthread-3) 20 |
-set seconds(walthread-4) 20 |
-set seconds(walthread-5) 1 |
- |
-# The parameter is the name of a variable in the callers context. The |
-# variable may or may not exist when this command is invoked. |
-# |
-# If the variable does exist, its value is returned. Otherwise, this |
-# command uses [vwait] to wait until it is set, then returns the value. |
-# In other words, this is a version of the [set VARNAME] command that |
-# blocks until a variable exists. |
-# |
-proc wait_for_var {varname} { |
- if {0==[uplevel [list info exists $varname]]} { |
- uplevel [list vwait $varname] |
- } |
- uplevel [list set $varname] |
-} |
- |
-# The argument is the name of a list variable in the callers context. The |
-# first element of the list is removed and returned. For example: |
-# |
-# set L {a b c} |
-# set x [lshift L] |
-# assert { $x == "a" && $L == "b c" } |
-# |
-proc lshift {lvar} { |
- upvar $lvar L |
- set ret [lindex $L 0] |
- set L [lrange $L 1 end] |
- return $ret |
-} |
- |
- |
-#------------------------------------------------------------------------- |
-# do_thread_test TESTNAME OPTIONS... |
-# |
-# where OPTIONS are: |
-# |
-# -seconds SECONDS How many seconds to run the test for |
-# -init SCRIPT Script to run before test. |
-# -thread NAME COUNT SCRIPT Scripts to run in threads (or processes). |
-# -processes BOOLEAN True to use processes instead of threads. |
-# -check SCRIPT Script to run after test. |
-# |
-proc do_thread_test {args} { |
- |
- set A $args |
- |
- set P(testname) [lshift A] |
- set P(seconds) 5 |
- set P(init) "" |
- set P(threads) [list] |
- set P(processes) 0 |
- set P(check) { |
- set ic [db eval "PRAGMA integrity_check"] |
- if {$ic != "ok"} { error $ic } |
- } |
- |
- unset -nocomplain ::done |
- |
- while {[llength $A]>0} { |
- set a [lshift A] |
- switch -glob -- $a { |
- -seconds { |
- set P(seconds) [lshift A] |
- } |
- |
- -init { |
- set P(init) [lshift A] |
- } |
- |
- -processes { |
- set P(processes) [lshift A] |
- } |
- |
- -check { |
- set P(check) [lshift A] |
- } |
- |
- -thread { |
- set name [lshift A] |
- set count [lshift A] |
- set prg [lshift A] |
- lappend P(threads) [list $name $count $prg] |
- } |
- |
- default { |
- error "Unknown option: $a" |
- } |
- } |
- } |
- |
- if {$P(seconds) == 0} { |
- puts "Skipping $P(testname)" |
- return |
- } |
- |
- puts "Running $P(testname) for $P(seconds) seconds..." |
- |
- catch { db close } |
- forcedelete test.db test.db-journal test.db-wal |
- |
- sqlite3 db test.db |
- eval $P(init) |
- catch { db close } |
- |
- foreach T $P(threads) { |
- set name [lindex $T 0] |
- set count [lindex $T 1] |
- set prg [lindex $T 2] |
- |
- for {set i 1} {$i <= $count} {incr i} { |
- set vars " |
- set E(pid) $i |
- set E(nthread) $count |
- set E(seconds) $P(seconds) |
- " |
- set program [string map [list %TEST% $prg %VARS% $vars] { |
- |
- %VARS% |
- |
- proc usleep {ms} { |
- set ::usleep 0 |
- after $ms {set ::usleep 1} |
- vwait ::usleep |
- } |
- |
- proc integrity_check {{db db}} { |
- set ic [$db eval {PRAGMA integrity_check}] |
- if {$ic != "ok"} {error $ic} |
- } |
- |
- proc busyhandler {n} { usleep 10 ; return 0 } |
- |
- sqlite3 db test.db |
- db busy busyhandler |
- db eval { SELECT randomblob($E(pid)*5) } |
- |
- set ::finished 0 |
- after [expr $E(seconds) * 1000] {set ::finished 1} |
- proc tt_continue {} { update ; expr ($::finished==0) } |
- |
- set rc [catch { %TEST% } msg] |
- |
- catch { db close } |
- list $rc $msg |
- }] |
- |
- if {$P(processes)==0} { |
- sqlthread spawn ::done($name,$i) $program |
- } else { |
- testfixture_nb ::done($name,$i) $program |
- } |
- } |
- } |
- |
- set report " Results:" |
- foreach T $P(threads) { |
- set name [lindex $T 0] |
- set count [lindex $T 1] |
- set prg [lindex $T 2] |
- |
- set reslist [list] |
- for {set i 1} {$i <= $count} {incr i} { |
- set res [wait_for_var ::done($name,$i)] |
- lappend reslist [lindex $res 1] |
- do_test $P(testname).$name.$i [list lindex $res 0] 0 |
- } |
- |
- append report " $name $reslist" |
- } |
- puts $report |
- |
- sqlite3 db test.db |
- set res "" |
- if {[catch $P(check) msg]} { set res $msg } |
- do_test $P(testname).check [list set {} $res] "" |
-} |
- |
-# A wrapper around [do_thread_test] which runs the specified test twice. |
-# Once using processes, once using threads. This command takes the same |
-# arguments as [do_thread_test], except specifying the -processes switch |
-# is illegal. |
-# |
-proc do_thread_test2 {args} { |
- set name [lindex $args 0] |
- if {[lsearch $args -processes]>=0} { error "bad option: -processes"} |
- uplevel [lreplace $args 0 0 do_thread_test "$name-threads" -processes 0] |
- uplevel [lreplace $args 0 0 do_thread_test "$name-processes" -processes 1] |
-} |
- |
-#-------------------------------------------------------------------------- |
-# Start 10 threads. Each thread performs both read and write |
-# transactions. Each read transaction consists of: |
-# |
-# 1) Reading the md5sum of all but the last table row, |
-# 2) Running integrity check. |
-# 3) Reading the value stored in the last table row, |
-# 4) Check that the values read in steps 1 and 3 are the same, and that |
-# the md5sum of all but the last table row has not changed. |
-# |
-# Each write transaction consists of: |
-# |
-# 1) Modifying the contents of t1 (inserting, updating, deleting rows). |
-# 2) Appending a new row to the table containing the md5sum() of all |
-# rows in the table. |
-# |
-# Each of the N threads runs N read transactions followed by a single write |
-# transaction in a loop as fast as possible. |
-# |
-# There is also a single checkpointer thread. It runs the following loop: |
-# |
-# 1) Execute "PRAGMA wal_checkpoint" |
-# 2) Sleep for 500 ms. |
-# |
-do_thread_test2 walthread-1 -seconds $seconds(walthread-1) -init { |
- execsql { |
- PRAGMA journal_mode = WAL; |
- CREATE TABLE t1(x PRIMARY KEY); |
- PRAGMA lock_status; |
- INSERT INTO t1 VALUES(randomblob(100)); |
- INSERT INTO t1 VALUES(randomblob(100)); |
- INSERT INTO t1 SELECT md5sum(x) FROM t1; |
- } |
-} -thread main 10 { |
- |
- proc read_transaction {} { |
- set results [db eval { |
- BEGIN; |
- PRAGMA integrity_check; |
- SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1); |
- SELECT x FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1); |
- SELECT md5sum(x) FROM t1 WHERE rowid != (SELECT max(rowid) FROM t1); |
- COMMIT; |
- }] |
- |
- if {[llength $results]!=4 |
- || [lindex $results 0] != "ok" |
- || [lindex $results 1] != [lindex $results 2] |
- || [lindex $results 2] != [lindex $results 3] |
- } { |
- error "Failed read transaction: $results" |
- } |
- } |
- |
- proc write_transaction {} { |
- db eval { |
- BEGIN; |
- INSERT INTO t1 VALUES(randomblob(101 + $::E(pid))); |
- INSERT INTO t1 VALUES(randomblob(101 + $::E(pid))); |
- INSERT INTO t1 SELECT md5sum(x) FROM t1; |
- COMMIT; |
- } |
- } |
- |
- # Turn off auto-checkpoint. Otherwise, an auto-checkpoint run by a |
- # writer may cause the dedicated checkpoint thread to return an |
- # SQLITE_BUSY error. |
- # |
- db eval { PRAGMA wal_autocheckpoint = 0 } |
- |
- set nRun 0 |
- while {[tt_continue]} { |
- read_transaction |
- write_transaction |
- incr nRun |
- } |
- set nRun |
- |
-} -thread ckpt 1 { |
- set nRun 0 |
- while {[tt_continue]} { |
- db eval "PRAGMA wal_checkpoint" |
- usleep 500 |
- incr nRun |
- } |
- set nRun |
-} |
- |
-#-------------------------------------------------------------------------- |
-# This test has clients run the following procedure as fast as possible |
-# in a loop: |
-# |
-# 1. Open a database handle. |
-# 2. Execute a read-only transaction on the db. |
-# 3. Do "PRAGMA journal_mode = XXX", where XXX is one of WAL or DELETE. |
-# Ignore any SQLITE_BUSY error. |
-# 4. Execute a write transaction to insert a row into the db. |
-# 5. Run "PRAGMA integrity_check" |
-# |
-# At present, there are 4 clients in total. 2 do "journal_mode = WAL", and |
-# two do "journal_mode = DELETE". |
-# |
-# Each client returns a string of the form "W w, R r", where W is the |
-# number of write-transactions performed using a WAL journal, and D is |
-# the number of write-transactions performed using a rollback journal. |
-# For example, "192 w, 185 r". |
-# |
-do_thread_test2 walthread-2 -seconds $seconds(walthread-2) -init { |
- execsql { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE) } |
-} -thread RB 2 { |
- |
- db close |
- set nRun 0 |
- set nDel 0 |
- while {[tt_continue]} { |
- sqlite3 db test.db |
- db busy busyhandler |
- db eval { SELECT * FROM sqlite_master } |
- catch { db eval { PRAGMA journal_mode = DELETE } } |
- db eval { |
- BEGIN; |
- INSERT INTO t1 VALUES(NULL, randomblob(100+$E(pid))); |
- } |
- incr nRun 1 |
- incr nDel [file exists test.db-journal] |
- if {[file exists test.db-journal] + [file exists test.db-wal] != 1} { |
- error "File-system looks bad..." |
- } |
- db eval COMMIT |
- |
- integrity_check |
- db close |
- } |
- list $nRun $nDel |
- set {} "[expr $nRun-$nDel] w, $nDel r" |
- |
-} -thread WAL 2 { |
- db close |
- set nRun 0 |
- set nDel 0 |
- while {[tt_continue]} { |
- sqlite3 db test.db |
- db busy busyhandler |
- db eval { SELECT * FROM sqlite_master } |
- catch { db eval { PRAGMA journal_mode = WAL } } |
- db eval { |
- BEGIN; |
- INSERT INTO t1 VALUES(NULL, randomblob(110+$E(pid))); |
- } |
- incr nRun 1 |
- incr nDel [file exists test.db-journal] |
- if {[file exists test.db-journal] + [file exists test.db-wal] != 1} { |
- error "File-system looks bad..." |
- } |
- db eval COMMIT |
- |
- integrity_check |
- db close |
- } |
- set {} "[expr $nRun-$nDel] w, $nDel r" |
-} |
- |
-do_thread_test walthread-3 -seconds $seconds(walthread-3) -init { |
- execsql { |
- PRAGMA journal_mode = WAL; |
- CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2); |
- CREATE INDEX i1 ON t1(sum1); |
- CREATE INDEX i2 ON t1(sum2); |
- INSERT INTO t1 VALUES(0, 0, 0); |
- } |
-} -thread t 10 { |
- |
- set nextwrite $E(pid) |
- |
- proc wal_hook {zDb nEntry} { |
- if {$nEntry>10} { |
- set rc [catch { db eval {PRAGMA wal_checkpoint} } msg] |
- if {$rc && $msg != "database is locked"} { error $msg } |
- } |
- return 0 |
- } |
- db wal_hook wal_hook |
- |
- while {[tt_continue]} { |
- set max 0 |
- while { $max != ($nextwrite-1) && [tt_continue] } { |
- set max [db eval { SELECT max(cnt) FROM t1 }] |
- } |
- |
- if {[tt_continue]} { |
- set sum1 [db eval { SELECT sum(cnt) FROM t1 }] |
- set sum2 [db eval { SELECT sum(sum1) FROM t1 }] |
- db eval { INSERT INTO t1 VALUES($nextwrite, $sum1, $sum2) } |
- incr nextwrite $E(nthread) |
- integrity_check |
- } |
- } |
- |
- set {} ok |
-} -check { |
- puts " Final db contains [db eval {SELECT count(*) FROM t1}] rows" |
- puts " Final integrity-check says: [db eval {PRAGMA integrity_check}]" |
- |
- # Check that the contents of the database are Ok. |
- set c 0 |
- set s1 0 |
- set s2 0 |
- db eval { SELECT cnt, sum1, sum2 FROM t1 ORDER BY cnt } { |
- if {$c != $cnt || $s1 != $sum1 || $s2 != $sum2} { |
- error "database content is invalid" |
- } |
- incr s2 $s1 |
- incr s1 $c |
- incr c 1 |
- } |
-} |
- |
-do_thread_test2 walthread-4 -seconds $seconds(walthread-4) -init { |
- execsql { |
- PRAGMA journal_mode = WAL; |
- CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); |
- } |
-} -thread r 1 { |
- # This connection only ever reads the database. Therefore the |
- # busy-handler is not required. Disable it to check that this is true. |
- # |
- # UPDATE: That is no longer entirely true - as we don't use a blocking |
- # lock to enter RECOVER state. Which means there is a small chance a |
- # reader can see an SQLITE_BUSY. |
- # |
- while {[tt_continue]} { |
- integrity_check |
- } |
- set {} ok |
-} -thread w 1 { |
- |
- proc wal_hook {zDb nEntry} { |
- if {$nEntry>15} {db eval {PRAGMA wal_checkpoint}} |
- return 0 |
- } |
- db wal_hook wal_hook |
- set row 1 |
- while {[tt_continue]} { |
- db eval { REPLACE INTO t1 VALUES($row, randomblob(300)) } |
- incr row |
- if {$row == 10} { set row 1 } |
- } |
- |
- set {} ok |
-} |
- |
- |
-# This test case attempts to provoke a deadlock condition that existed in |
-# the unix VFS at one point. The problem occurred only while recovering a |
-# very large wal file (one that requires a wal-index larger than the |
-# initial default allocation of 64KB). |
-# |
-do_thread_test walthread-5 -seconds $seconds(walthread-5) -init { |
- |
- proc log_file_size {nFrame pgsz} { |
- expr {12 + ($pgsz+16)*$nFrame} |
- } |
- |
- execsql { |
- PRAGMA page_size = 1024; |
- PRAGMA journal_mode = WAL; |
- CREATE TABLE t1(x); |
- BEGIN; |
- INSERT INTO t1 VALUES(randomblob(900)); |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32768 */ |
- INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 65536 */ |
- COMMIT; |
- } |
- |
- forcecopy test.db-wal bak.db-wal |
- forcecopy test.db bak.db |
- db close |
- |
- forcecopy bak.db-wal test.db-wal |
- forcecopy bak.db test.db |
- |
- if {[file size test.db-wal] < [log_file_size [expr 64*1024] 1024]} { |
- error "Somehow failed to create a large log file" |
- } |
- puts "Database with large log file recovered. Now running clients..." |
-} -thread T 5 { |
- db eval { SELECT count(*) FROM t1 } |
-} |
-unset -nocomplain seconds |
- |
-finish_test |