]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add some tests and fixes surrounding exclusive-access mode and the pager change-count...
authordanielk1977 <danielk1977@noemail.net>
Mon, 26 Mar 2007 10:27:18 +0000 (10:27 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Mon, 26 Mar 2007 10:27:18 +0000 (10:27 +0000)
FossilOrigin-Name: 72cb2e1a73cd09d32900bb473377f66ff55058fb

manifest
manifest.uuid
src/pager.c
test/exclusive.test
test/exclusive2.test [new file with mode: 0644]

index 792649f6fffc61bc486995c1735f054163e3c016..25630ba70de999c6541520eaab9a537ad3a32d7d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssome\sdocumentation\sfor\spragma\slocking_mode.\s(CVS\s3715)
-D 2007-03-26T08:41:13
+C Add\ssome\stests\sand\sfixes\ssurrounding\sexclusive-access\smode\sand\sthe\spager\schange-counter.\s(CVS\s3716)
+D 2007-03-26T10:27:19
 F Makefile.in 1fe3d0b46e40fd684e1e61f8e8056cefed16de9f
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -86,7 +86,7 @@ F src/os_unix.c 4642f23ed0c1ae0f1440db1d2b4231348af69360
 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
 F src/os_win.c 1d1d0989b0f235751504292c2f28e81044be0d70
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c 5846d0c1b010145b656719c7579018f906f2663f
+F src/pager.c 4c83ffbb02386d0fd90eef51c16097c74e5b785a
 F src/pager.h 3c16500c25051536e43fb19e246e58fc7cb51d9f
 F src/parse.y bcfe366c1fd61cfc40e5344eb69a31997a821af0
 F src/pragma.c 9cb8b94e7d38ba35a86037bd517d07ba9870b4b2
@@ -199,7 +199,8 @@ F test/distinctagg.test 2b89d1c5220d966a30ba4b40430338669301188b
 F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52
 F test/enc2.test 45710bacfa9df29720bc84c067dfdf8c8ddfb797
 F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030
-F test/exclusive.test c2d8b75882a3f35057209e6d5e99737a1ef33d80
+F test/exclusive.test 83871f52ab1015dc1bfbf86b96e2ece29094d129
+F test/exclusive2.test 187993598a83257f4a1126a40d89144c01965500
 F test/expr.test c78843f730ccbe973d0c2ad1c99978f936893131
 F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce
 F test/format4.test bf3bed3b13c63abfb3cfec232597a319a31d0bcc
@@ -438,7 +439,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 899e60707bea0fabab2ff3ac8a3fbb676a539120
-R c95c47b55de39c81a885f5c3b87d8ccb
+P 394b174e59262a84c530ea73c367d8c389a681b5
+R b9cfbb38bcb177f91ab61bb6f0720497
 U danielk1977
-Z a34ef51e67b415410cd73312e1288145
+Z bbf2e9e72a548a49626e962c15cb3299
index 69c2948012efa240c6201461f70f19fe7e70e1b1..cd9a0bed8065615c8ba554bee7adf8a570d2b3e9 100644 (file)
@@ -1 +1 @@
-394b174e59262a84c530ea73c367d8c389a681b5
\ No newline at end of file
+72cb2e1a73cd09d32900bb473377f66ff55058fb
\ No newline at end of file
index 41528a8b46182c8993b747c96901129f895cf075..a078f7fe49b7f4ee364a6ca47eeffd097137c4cb 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.295 2007/03/26 08:05:12 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.296 2007/03/26 10:27:19 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -927,7 +927,7 @@ static int pager_unwritelock(Pager *pPager){
   }
   sqlite3PagerStmtCommit(pPager);
   if( pPager->stmtOpen && !pPager->exclusiveMode ){
-    if( pPager->exclusiveMode ){
+    if( !pPager->exclusiveMode ){
       sqlite3OsClose(&pPager->stfd);
       pPager->stmtOpen = 0;
     }else{
@@ -3897,23 +3897,25 @@ static int pager_incr_changecounter(Pager *pPager){
   u32 change_counter;
   int rc;
 
-  /* Open page 1 of the file for writing. */
-  rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
-  if( rc!=SQLITE_OK ) return rc;
-  rc = sqlite3PagerWrite(pPgHdr);
-  if( rc!=SQLITE_OK ) return rc;
-
-  /* Read the current value at byte 24. */
-  change_counter = retrieve32bits(pPgHdr, 24);
-
-  /* Increment the value just read and write it back to byte 24. */
-  change_counter++;
-  put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
-  pPager->iChangeCount = change_counter;
-
-  /* Release the page reference. */
-  sqlite3PagerUnref(pPgHdr);
-  pPager->changeCountDone = 1;
+  if( !pPager->changeCountDone ){
+    /* Open page 1 of the file for writing. */
+    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
+    if( rc!=SQLITE_OK ) return rc;
+    rc = sqlite3PagerWrite(pPgHdr);
+    if( rc!=SQLITE_OK ) return rc;
+  
+    /* Read the current value at byte 24. */
+    change_counter = retrieve32bits(pPgHdr, 24);
+  
+    /* Increment the value just read and write it back to byte 24. */
+    change_counter++;
+    put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
+    pPager->iChangeCount = change_counter;
+  
+    /* Release the page reference. */
+    sqlite3PagerUnref(pPgHdr);
+    pPager->changeCountDone = 1;
+  }
   return SQLITE_OK;
 }
 
index 56019805bf5bec780f1b28303ead648cf0f126e0..aff4e8313d5f09195bfdb803b003f596eccdedc9 100644 (file)
@@ -8,9 +8,11 @@
 #    May you share freely, never taking more than you give.
 #
 #***********************************************************************
-# This file implements regression tests for SQLite library.
+# This file implements regression tests for SQLite library. The focus
+# of these tests is exclusive access mode (i.e. the thing activated by 
+# "PRAGMA locking_mode = EXCLUSIVE").
 #
-# $Id: exclusive.test,v 1.2 2007/03/26 08:05:12 danielk1977 Exp $
+# $Id: exclusive.test,v 1.3 2007/03/26 10:27:19 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
diff --git a/test/exclusive2.test b/test/exclusive2.test
new file mode 100644 (file)
index 0000000..ee8cd66
--- /dev/null
@@ -0,0 +1,242 @@
+# 2007 March 24
+#
+# 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.
+#
+# $Id: exclusive2.test,v 1.1 2007/03/26 10:27:19 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable {!pager_pragmas} {
+  finish_test
+  return
+}
+
+proc pagerChangeCounter {filename {new ""}} {
+  set fd [open $filename a+]
+  fconfigure $fd -translation binary -encoding binary
+  if {$new ne ""} {
+    seek $fd 24
+    set a [expr {($new&0xFF000000)>>24}]
+    set b [expr {($new&0x00FF0000)>>16}]
+    set c [expr {($new&0x0000FF00)>>8}]
+    set d [expr {($new&0x000000FF)}]
+    puts $fd [binary format cccc $a $b $c $d]
+  }
+
+  seek $fd 24
+  foreach {a b c d} [list 0 0 0 0] {}
+  binary scan [read $fd 4] cccc a b c d
+  set  ret [expr ($a&0x000000FF)<<24]
+  incr ret [expr ($b&0x000000FF)<<16]
+  incr ret [expr ($c&0x000000FF)<<8]
+  incr ret [expr ($d&0x000000FF)<<0]
+
+  close $fd
+  return $ret
+}
+
+proc t1sig {{db db}} {
+  execsql {SELECT count(*), md5sum(a) FROM t1} $db
+}
+do_test exclusive2-1.0 {
+  pagerChangeCounter test.db
+} {0}
+
+#-----------------------------------------------------------------------
+# The following tests - exclusive2-1.X - check that:
+#
+# 1-3:   Build a database with connection 1, calculate a signature.
+# 4-9:   Modify the database using a second connection, then reset
+#        the pager change-counter to the value it had before the modifications.
+# 8:     Check that using the first connection, the database signature
+#        is still the same. This is because it uses the in-memory cache.
+#        It can't tell the db has changed because we reset the change-counter.
+# 9:     Increment the change-counter.
+# 10:    Ensure that the first connection now sees the updated database. It
+#        sees the change-counter has been incremented and discards the 
+#        invalid in-memory cache.
+#
+do_test exclusive2-1.1 {
+  execsql {
+    BEGIN;
+    CREATE TABLE t1(a UNIQUE);
+    INSERT INTO t1 VALUES(randstr(10, 400));
+    INSERT INTO t1 VALUES(randstr(10, 400));
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    COMMIT;
+    SELECT count(*) FROM t1;
+  }
+} {64}
+do_test exclusive2-1.2 {
+  set ::sig [t1sig]
+  pagerChangeCounter test.db
+} {1}
+do_test exclusive2-1.3 {
+  t1sig
+} $::sig
+do_test exclusive2-1.4 {
+  sqlite3 db2 test.db
+  t1sig db2
+} $::sig
+do_test exclusive2-1.5 {
+  execsql {
+    DELETE FROM t1;
+  } db2
+  expr {[t1sig db2] eq $::sig}
+} 0
+do_test exclusive2-1.6 {
+  pagerChangeCounter test.db
+} {2}
+do_test exclusive2-1.7 {
+  pagerChangeCounter test.db 1
+} {1}
+do_test exclusive2-1.9 {
+  t1sig
+  expr {[t1sig] eq $::sig}
+} {1}
+do_test exclusive2-1.10 {
+  pagerChangeCounter test.db 2
+} {2}
+do_test exclusive2-1.11 {
+  expr {[t1sig] eq $::sig}
+} {0}
+
+#--------------------------------------------------------------------
+# These tests - exclusive2-2.X - are similar to exclusive2-1.X, 
+# except that they are run with locking_mode=EXCLUSIVE.
+#
+# 1-3:   Build a database with exclusive-access connection 1, 
+#        calculate a signature.
+# 4:     Corrupt the database by writing 10000 bytes of garbage
+#        starting at the beginning of page 2. Check that connection 1
+#        still works. It should be accessing the in-memory cache.
+# 5-6:   Modify the dataase change-counter. Connection 1 still works
+#        entirely from in-memory cache, because it doesn't check the
+#        change-counter.
+# 7-8    Set the locking-mode back to normal. After the db is unlocked,
+#        SQLite detects the modified change-counter and discards the
+#        in-memory cache. Then it finds the corruption caused in step 4....
+#
+do_test exclusive2-2.1 {
+  execsql {PRAGMA locking_mode = exclusive;}
+  execsql {
+    BEGIN;
+    INSERT INTO t1 VALUES(randstr(10, 400));
+    INSERT INTO t1 VALUES(randstr(10, 400));
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    COMMIT;
+    SELECT count(*) FROM t1;
+  }
+} {64}
+do_test exclusive2-2.2 {
+  set ::sig [t1sig]
+  pagerChangeCounter test.db
+} {3}
+do_test exclusive2-2.3 {
+  t1sig
+} $::sig
+
+do_test exclusive2-2.4 {
+  set fd [open test.db a]
+  seek $fd 1024
+  puts -nonewline $fd [string repeat [binary format c 0] 10000]
+  t1sig
+} $::sig
+
+do_test exclusive2-2.5 {
+  pagerChangeCounter test.db 5
+} {5}
+do_test exclusive2-2.6 {
+  t1sig
+} $::sig
+do_test exclusive2-2.7 {
+  execsql {PRAGMA locking_mode = normal}
+  t1sig
+} $::sig
+
+do_test exclusive2-2.8 {
+  set rc [catch {t1sig} msg]
+  list $rc $msg
+} {1 {database disk image is malformed}}
+
+#--------------------------------------------------------------------
+# These tests - exclusive2-3.X - verify that the pager change-counter
+# is only incremented by the first change when in exclusive access
+# mode. In normal mode, the change-counter is incremented once
+# per write-transaction.
+#
+
+db close
+db2 close
+file delete -force test.db
+file delete -force test.db-journal
+
+do_test exclusive2-3.0 {
+  sqlite3 db test.db
+  execsql {
+    BEGIN;
+    CREATE TABLE t1(a UNIQUE);
+    INSERT INTO t1 VALUES(randstr(10, 400));
+    INSERT INTO t1 VALUES(randstr(10, 400));
+    COMMIT;
+  }
+  pagerChangeCounter test.db
+} {1}
+do_test exclusive2-3.1 {
+  execsql {
+    INSERT INTO t1 VALUES(randstr(10, 400));
+  }
+  pagerChangeCounter test.db
+} {2}
+do_test exclusive2-3.2 {
+  execsql {
+    INSERT INTO t1 VALUES(randstr(10, 400));
+  }
+  pagerChangeCounter test.db
+} {3}
+do_test exclusive2-3.3 {
+  execsql {
+    PRAGMA locking_mode = exclusive;
+    INSERT INTO t1 VALUES(randstr(10, 400));
+  }
+  pagerChangeCounter test.db
+} {4}
+do_test exclusive2-3.4 {
+  execsql {
+    INSERT INTO t1 VALUES(randstr(10, 400));
+  }
+  pagerChangeCounter test.db
+} {4}
+do_test exclusive2-3.5 {
+  execsql {
+    PRAGMA locking_mode = normal;
+    INSERT INTO t1 VALUES(randstr(10, 400));
+  }
+  pagerChangeCounter test.db
+} {4}
+do_test exclusive2-3.6 {
+  execsql {
+    INSERT INTO t1 VALUES(randstr(10, 400));
+  }
+  pagerChangeCounter test.db
+} {5}
+
+finish_test
+