]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add test file pager1.test, containing tests of inter-process locking in non-wal mode.
authordan <dan@noemail.net>
Tue, 15 Jun 2010 17:44:47 +0000 (17:44 +0000)
committerdan <dan@noemail.net>
Tue, 15 Jun 2010 17:44:47 +0000 (17:44 +0000)
FossilOrigin-Name: 6e43eed9310bae9ca5e91f8fd9eafc45a16b7019

manifest
manifest.uuid
test/lock_common.tcl
test/pager1.test [new file with mode: 0644]
test/permutations.test
test/quick.test

index 9c7a7211b75fc6310ffed3c6ffd58bf30673ea71..9124776a9a9956421945d28b1e933c128a902e3d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Run\sextra\siterations\sin\swal3.test\sto\sensure\stest\scoverage.
-D 2010-06-15T14:21:17
+C Add\stest\sfile\spager1.test,\scontaining\stests\sof\sinter-process\slocking\sin\snon-wal\smode.
+D 2010-06-15T17:44:48
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -484,7 +484,7 @@ F test/lock4.test f4f36271aa5ae1da449646bf43c7341f6b2b4c4e
 F test/lock5.test 6b1f78f09ad1522843dad571b76b321e6f439bf7
 F test/lock6.test 8df56060f396151777390982422c800d026e1722
 F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
-F test/lock_common.tcl 69d6b67f2ba63968ec2173bcd7310c5c7eca00a2
+F test/lock_common.tcl c03802ef77c3864f1a7d812b0760b59563f2613b
 F test/lookaside.test 1dd350dc6dff015c47c07fcc5a727a72fc5bae02
 F test/main.test 2be2352ac77ac5b238c6337a5469aeeef57677e6
 F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
@@ -533,17 +533,18 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
 F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
 F test/null.test a8b09b8ed87852742343b33441a9240022108993
 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
+F test/pager1.test dcc50ea9c4fc8d6d7101733644655c8395826e9b
 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
 F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
 F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
 F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
-F test/permutations.test 28f46dfcc880e15ec7ab1ff36d12af765a0e3bc4
+F test/permutations.test 403099a8e191b43e5df19b8199b80178b3ece1d6
 F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a
 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
-F test/quick.test d2a697cf6d6db2725649670859365ef601289f96
+F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
@@ -820,7 +821,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 03c0f4fd9cbb655477b63ebbb6af7822715644aa
-R a2075e9740cf75b8937129b9cbcda629
+P ea80cbe51e33d6a3f15a4ad56f360fc5323866de
+R 2d037491154b033cfc4dcca7e9e50afd
 U dan
-Z 73996e320eea715ffc64316616623fba
+Z 2d173a77ac2cf0416b30cd54aeed8e9e
index 7b71e38dc6354f23a027c1094305cdf668a16278..8f08b18d48b179399331cdbe2ff895969747620d 100644 (file)
@@ -1 +1 @@
-ea80cbe51e33d6a3f15a4ad56f360fc5323866de
\ No newline at end of file
+6e43eed9310bae9ca5e91f8fd9eafc45a16b7019
\ No newline at end of file
index 0683bbd389b04577b4c2a77eb9065be844506369..83d20d634087c593ea28520fa74965a00a4446b2 100644 (file)
@@ -30,6 +30,7 @@ proc launch_testfixture {} {
 
 # Execute a command in a child testfixture process, connected by two-way
 # channel $chan. Return the result of the command, or an error message.
+#
 proc testfixture {chan cmd} {
   puts $chan $cmd
   puts $chan OVER
@@ -37,7 +38,9 @@ proc testfixture {chan cmd} {
   while { 1 } {
     set line [gets $chan]
     if { $line == "OVER" } { 
-      return $r
+      set res [lindex $r 1]
+      if { [lindex $r 0] } { error $res }
+      return $res
     }
     if {[eof $chan]} {
       return "ERROR: Child process hung up"
@@ -55,7 +58,7 @@ proc testfixture_nb_cb {varname chan} {
   }
 
   if { $line == "OVER" } {
-    set $varname $::tfnb($chan)
+    set $varname [lindex $::tfnb($chan) 1]
     unset ::tfnb($chan)
     close $chan
   } else {
@@ -89,8 +92,8 @@ puts $f {
     puts $l "READ $line"
     if { $line == "OVER" } {
       set rc [catch {eval $script} result]
-      puts $result
-      puts $l "WRITE $result"
+      puts [list $rc $result]
+      puts $l "WRITE [list $rc $result]"
       puts OVER
       puts $l "WRITE OVER"
       flush stdout
diff --git a/test/pager1.test b/test/pager1.test
new file mode 100644 (file)
index 0000000..26ae518
--- /dev/null
@@ -0,0 +1,194 @@
+# 2010 June 15
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/malloc_common.tcl
+
+foreach code [list {
+  set ::code2_chan [launch_testfixture]
+  set ::code3_chan [launch_testfixture]
+  proc code2 {tcl} { testfixture $::code2_chan $tcl }
+  proc code3 {tcl} { testfixture $::code3_chan $tcl }
+  set tn 1
+} {
+  proc code2 {tcl} { uplevel #0 $tcl }
+  proc code3 {tcl} { uplevel #0 $tcl }
+  set tn 2
+}] {
+
+  faultsim_delete_and_reopen
+
+  # Open connections [db2] and [db3]. Depending on which iteration this
+  # is, the connections may be created in this interpreter, or in 
+  # interpreters running in other OS processes. As such, the [db2] and [db3]
+  # commands should only be accessed within [code2] and [code3] blocks,
+  # respectively.
+  #
+  eval $code
+  code2 { sqlite3 db2 test.db }
+  code3 { sqlite3 db3 test.db }
+  
+  # Shorthand commands. Execute SQL using database connection [db2] or 
+  # [db3]. Return the results.
+  #
+  proc sql1 {sql} { db eval $sql }
+  proc sql2 {sql} { code2 [list db2 eval $sql] }
+  proc sql3 {sql} { code3 [list db3 eval $sql] }
+
+  proc csql1 {sql} { list [catch { sql1 $sql } msg] $msg }
+  proc csql2 {sql} { list [catch { sql2 $sql } msg] $msg }
+  proc csql3 {sql} { list [catch { sql3 $sql } msg] $msg }
+
+  # Create and populate a database table using connection [db]. Check 
+  # that connections [db2] and [db3] can see the schema and content.
+  #
+  do_test pager1-$tn.1 {
+    sql1 {
+      CREATE TABLE t1(a PRIMARY KEY, b);
+      CREATE INDEX i1 ON t1(b);
+      INSERT INTO t1 VALUES(1, 'one');
+      INSERT INTO t1 VALUES(2, 'two');
+    }
+  } {}
+  do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
+  do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
+
+  # Open a transaction and add a row using [db]. This puts [db] in
+  # RESERVED state. Check that connections [db2] and [db3] can still
+  # read the database content as it was before the transaction was
+  # opened. [db] should see the inserted row.
+  #
+  do_test pager1-$tn.4 {
+    sql1 {
+      BEGIN;
+        INSERT INTO t1 VALUES(3, 'three');
+    }
+  } {}
+  do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
+  do_test pager1-$tn.6 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
+  do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+
+  # [db] still has an open write transaction. Check that this prevents
+  # other connections (specifically [db2]) from writing to the database.
+  #
+  # Even if [db2] opens a transaction first, it may not write to the
+  # database. After the attempt to write the db within a transaction, 
+  # [db2] is left with an open transaction, but not a read-lock on
+  # the main database. So it does not prevent [db] from committing.
+  #
+  do_test pager1-$tn.8 { 
+    csql2 { UPDATE t1 SET a = a + 10 }
+  } {1 {database is locked}}
+  do_test pager1-$tn.9 { 
+    csql2 { 
+      BEGIN;
+      UPDATE t1 SET a = a + 10;
+    }
+  } {1 {database is locked}}
+
+  # Have [db] commit its transactions. Check the other connections can
+  # now see the new database content.
+  #
+  do_test pager1-$tn.10 { sql1 { COMMIT } } {}
+  do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+  do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+  do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+
+  # Check that, as noted above, [db2] really did keep an open transaction
+  # after the attempt to write the database failed.
+  #
+  do_test pager1-$tn.14 { 
+    csql2 { BEGIN } 
+  } {1 {cannot start a transaction within a transaction}}
+  do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
+
+  # Have [db2] open a transaction and take a read-lock on the database.
+  # Check that this prevents [db] from writing to the database (outside
+  # of any transaction). After this fails, check that [db3] can read
+  # the db (showing that [db] did not take a PENDING lock etc.)
+  #
+  do_test pager1-$tn.15 { 
+    sql2 { BEGIN; SELECT * FROM t1; }
+  } {1 one 2 two 3 three}
+  do_test pager1-$tn.16 { 
+    csql1 { UPDATE t1 SET a = a + 10 }
+  } {1 {database is locked}}
+  do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+
+  # This time, have [db] open a transaction before writing the database.
+  # This works - [db] gets a RESERVED lock which does not conflict with
+  # the SHARED lock [db2] is holding.
+  #
+  do_test pager1-$tn.18 { 
+    sql1 { 
+      BEGIN;  
+      UPDATE t1 SET a = a + 10; 
+    }
+  } {}
+  do_test pager1-$tn-19 { 
+    sql1 { PRAGMA lock_status } 
+  } {main reserved temp closed}
+  do_test pager1-$tn-20 { 
+    sql2 { PRAGMA lock_status } 
+  } {main shared temp closed}
+
+  # Check that all connections can still read the database. Only [db] sees
+  # the updated content (as the transaction has not been committed yet).
+  #
+  do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
+  do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+  do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
+
+  # Because [db2] still has the SHARED lock, [db] is unable to commit the
+  # transaction. If it tries, an error is returned and the connection 
+  # upgrades to a PENDING lock.
+  #
+  # Once this happens, [db] can read the database and see the new content,
+  # [db2] (still holding SHARED) can still read the old content, but [db3]
+  # (not holding any lock) is prevented by [db]'s PENDING from reading
+  # the database.
+  #
+  do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
+  do_test pager1-$tn-25 { 
+    sql1 { PRAGMA lock_status } 
+  } {main pending temp closed}
+  do_test pager1-$tn.26 { sql1 { SELECT * FROM t1  } } {11 one 12 two 13 three}
+  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1  } } {1 one 2 two 3 three}
+  do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
+
+  # Have [db2] commit its read transaction, releasing the SHARED lock it
+  # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
+  # is still holding a PENDING).
+  #
+  do_test pager1-$tn.29 { sql2 { COMMIT } } {}
+  do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
+  do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
+
+  # [db] is now able to commit the transaction. Once the transaction is 
+  # committed, all three connections can read the new content.
+  #
+  do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
+  do_test pager1-$tn.26 { sql1 { COMMIT } } {}
+  do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
+  do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
+  do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
+
+  code2 { db2 close }
+  code3 { db3 close }
+  catch { close $::code2_chan }
+  catch { close $::code3_chan }
+}
+
+finish_test
+
index 2ae739fbbce24a42636d4b27a530f115a7a7b588..10a18dad0be15dbbd21172501230ef76d6d4445a 100644 (file)
@@ -9,7 +9,6 @@
 #
 #***********************************************************************
 #
-# $Id: permutations.test,v 1.51 2009/07/01 18:09:02 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -48,6 +47,7 @@ proc test_suite {name args} {
 
   set     ::testspec($name) [array get options]
   lappend ::testsuitelist $name
+
 }
 
 #-------------------------------------------------------------------------
@@ -120,6 +120,7 @@ set allquicktests [test_set $alltests -exclude {
 #   full
 #   veryquick_plus_notify2
 #
+lappend ::testsuitelist xxx
 
 test_suite "veryquick" -description {
   "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
@@ -150,11 +151,11 @@ test_suite "full" -description {
   unset -nocomplain ::G(isquick)
 }
 
+lappend ::testsuitelist xxx
 #-------------------------------------------------------------------------
 # Define the coverage related test suites:
 #
 #   coverage-wal
-#   coverage-fkey
 #
 test_suite "coverage-wal" -description {
   Coverage tests for file wal.c.
@@ -164,8 +165,14 @@ test_suite "coverage-wal" -description {
   walfault.test
 } 
 
+test_suite "coverage-pager" -description {
+  Coverage tests for file pager.c.
+} -files {
+  pager1.test
+} 
 
 
+lappend ::testsuitelist xxx
 #-------------------------------------------------------------------------
 # Define the permutation test suites:
 #
@@ -803,13 +810,21 @@ proc run_test_suite {name} {
 }
 
 proc help {} {
+  puts "Usage: $::argv0 TESTSUITE ?TESTFILE?"
+  puts ""
+  puts "Available test-suites are:"
   foreach k $::testsuitelist {
-    array set o $::testspec($k)
-    puts "Test suite: \"$k\""
-    set d [string trim $o(-description)]
-    set d [regsub {\n *} $d "\n  "]
-    puts "  $d"
-    puts ""
+    if {[info exists ::testspec($k)]==0} {
+      puts "         ----------------------------------------"
+      puts ""
+    } else {
+      array set o $::testspec($k)
+      puts "Test suite: \"$k\""
+      set d [string trim $o(-description)]
+      set d [regsub {\n *} $d "\n  "]
+      puts "  $d"
+      puts ""
+    }
   }
   exit -1
 }
index af9ee0cfb2633ae5febb8f27bde37d8eb85b1f9a..974b02de97de2af4468b92991026e5200c67d905 100644 (file)
 set testdir [file dirname $argv0]
 source $testdir/permutations.test
 
-if {[info exists env(QUICKTEST_INCLUDE]} {
-  # A hack so that releasetest.tcl keeps working.
-  run_test_suite quick_plus_notify2
-} else {
-  run_test_suite quick
-}
+run_test_suite quick
 
 finish_test