From: dan Date: Thu, 29 Apr 2010 08:47:28 +0000 (+0000) Subject: Add tests to walthread.test. X-Git-Tag: version-3.7.2~455^2~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b4e3a6f72f38be188f5b13933306df2fd0f491b6;p=thirdparty%2Fsqlite.git Add tests to walthread.test. FossilOrigin-Name: 9e891e7543ea4d7dee76deb2456af940f4cac49b --- diff --git a/manifest b/manifest index 8d7772b612..d16501f28f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\stest\sto\swalthread.test\sfor\schanging\sbetween\sWAL\sand\srollback\smodes. -D 2010-04-28T18:17:23 +C Add\stests\sto\swalthread.test. +D 2010-04-29T08:47:28 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in d83a0ffef3dcbfb08b410a6c6dd6c009ec9167fb F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -764,7 +764,7 @@ F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1 F test/walhook.test 287a69d662939604f2e0452dace2cec8ef634d5e F test/walmode.test 40119078da084e6a7403ba57485d5a86ee0e2646 F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2 -F test/walthread.test ce1d0fc9905cf8a7cf1a61dbcafcbd3434166236 +F test/walthread.test 8fdce1721bf01e88a1f83a93ce7ae2e7668bcb26 F test/where.test de337a3fe0a459ec7c93db16a519657a90552330 F test/where2.test 45eacc126aabb37959a387aa83e59ce1f1f03820 F test/where3.test aa44a9b29e8c9f3d7bb94a3bb3a95b31627d520d @@ -808,7 +808,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 13d2d5a66e9eaa81aa6314354201ee1fbd2b3824 -R 03ea219fce1817690b6cb9bee0a76d8a +P da229e44bd4a5d512261da05958d560808c9889f +R f40b5481d2db02fd1a8b59b3cbe35412 U dan -Z e37b4277b60d879edbf1e6cb6d434b3c +Z 9a86a68774ea80363d82258dc9f803a1 diff --git a/manifest.uuid b/manifest.uuid index c424e5c417..cfa4e15520 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -da229e44bd4a5d512261da05958d560808c9889f \ No newline at end of file +9e891e7543ea4d7dee76deb2456af940f4cac49b \ No newline at end of file diff --git a/test/walthread.test b/test/walthread.test index 057ba2396f..353b7e42dd 100644 --- a/test/walthread.test +++ b/test/walthread.test @@ -21,11 +21,12 @@ if {[run_thread_tests]==0} { finish_test ; return } set sqlite_walsummary_mmap_incr 64 -# The number of threads to start. And the amount of time to run the test -# for. Respectively. +# How long, in seconds, to run each test for. If a test is set to run for +# 0 seconds, it is omitted entirely. # -set NTHREAD 10 -set SECONDS 5 +set seconds(walthread-1) 0 +set seconds(walthread-2) 0 +set seconds(walthread-3) 20 # The parameter is the name of a variable in the callers context. The # variable may or may not exist when this command is invoked. @@ -42,6 +43,13 @@ proc wait_for_var {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] @@ -59,11 +67,10 @@ proc lshift {lvar} { # -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} { - #if {[string match walthread-2* [lindex $args 0]]==0} return - set A $args set P(testname) [lshift A] @@ -71,6 +78,10 @@ proc do_thread_test {args} { 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 @@ -89,6 +100,10 @@ proc do_thread_test {args} { set P(processes) [lshift A] } + -check { + set P(check) [lshift A] + } + -thread { set name [lshift A] set count [lshift A] @@ -102,6 +117,11 @@ proc do_thread_test {args} { } } + if {$P(seconds) == 0} { + puts "Skipping $P(testname)" + return + } + puts "Running $P(testname) for $P(seconds) seconds..." catch { db close } @@ -117,23 +137,34 @@ proc do_thread_test {args} { set prg [lindex $T 2] for {set i 1} {$i <= $count} {incr i} { - set program [string map [list %TEST% $prg %SECONDS% $P(seconds) %I% $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] { - set tid %I% + %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($tid*5) } + db eval { SELECT randomblob($E(pid)*5) } set ::finished 0 - after [expr %SECONDS% * 1000] {set ::finished 1} + after [expr $E(seconds) * 1000] {set ::finished 1} proc tt_continue {} { update ; expr ($::finished==0) } set rc [catch { %TEST% } msg] @@ -166,10 +197,28 @@ proc do_thread_test {args} { 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 NTHREAD threads. Each thread performs both read and write +# 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, @@ -192,124 +241,187 @@ proc do_thread_test {args} { # 1) Execute "PRAGMA checkpoint" # 2) Sleep for 500 ms. # - -foreach {mode name} { - 0 walthread-1-threads - 1 walthread-1-processes -} { - do_thread_test $name -processes $mode -seconds $SECONDS -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 $NTHREAD { - - 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(100)); - INSERT INTO t1 VALUES(randomblob(100)); - INSERT INTO t1 SELECT md5sum(x) FROM t1; - COMMIT; - } - } - - set nRun 0 - while {[tt_continue]} { - read_transaction - write_transaction - incr nRun +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" } - set nRun - - } -thread ckpt 1 { - set nRun 0 - while {[tt_continue]} { - db eval "PRAGMA checkpoint" - usleep 500 - incr nRun + } + + proc write_transaction {} { + db eval { + BEGIN; + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 SELECT md5sum(x) FROM t1; + COMMIT; } - set nRun } + + 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 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" # -foreach {mode name} { - 0 walthread-2-threads - 1 walthread-2-processes -} { - do_thread_test $name -processes $mode -seconds $SECONDS -init { - execsql { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE) } - } -thread RB 2 { +# 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 - 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+$tid)); - } - incr nRun 1 - incr nDel [file exists test.db-journal] - db eval COMMIT + } + list $nRun $nDel + set {} "[expr $nRun-$nDel] w, $nDel r" - set ic [db eval {PRAGMA integrity_check}] - if {$ic != "ok"} { error $ic } - db close +} -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..." } - list $nRun $nDel + db eval COMMIT - } -thread WAL 2 { + integrity_check db close - set nRun 0 - set nWal 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+$tid)); - } - incr nRun 1 - incr nWal [file exists test.db-wal] - db eval COMMIT + } + set {} "[expr $nRun-$nDel] w, $nDel r" +} + +do_thread_test2 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} { return 1 } + 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 ic [db eval {PRAGMA integrity_check}] - if {$ic != "ok"} { error $ic } - db close + 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" } - list $nRun $nWal + incr s2 $s1 + incr s1 $c + incr c 1 } }