]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a but in the WAL checkpoint code causing SQLite to use an inconsistent cache...
authordan <dan@noemail.net>
Thu, 29 Apr 2010 14:51:33 +0000 (14:51 +0000)
committerdan <dan@noemail.net>
Thu, 29 Apr 2010 14:51:33 +0000 (14:51 +0000)
FossilOrigin-Name: d1cadeed4eea20d8892726cc8c69f4f3f57d0cd4

manifest
manifest.uuid
src/wal.c
test/wal.test
test/walthread.test

index d16501f28fe27b17da11bc187730c8fa8d48860a..52e87c60a97e0c62714d699bc85e50a11de674db 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\stests\sto\swalthread.test.
-D 2010-04-29T08:47:28
+C Fix\sa\sbut\sin\sthe\sWAL\scheckpoint\scode\scausing\sSQLite\sto\suse\san\sinconsistent\scache\sin\sa\ssubsequent\stransaction.
+D 2010-04-29T14:51:33
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in d83a0ffef3dcbfb08b410a6c6dd6c009ec9167fb
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -221,7 +221,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
 F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
-F src/wal.c d63318e8e73f9ed1a6f3c277f71022024f38a7c3
+F src/wal.c b1c6868b975a67f6f4dd2cd612eeace4117eb98f
 F src/wal.h c60781e78e394af07ece3b64a11192eb442241c1
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
 F src/where.c faadd9c2bf08868e5135192b44e0d753e363a885
@@ -758,13 +758,13 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
-F test/wal.test bc99b1656b721fddd2dfeea0b0e77b147e40e6da
+F test/wal.test d6fa4631310f95ac7d22f74b29c4b197f519d65b
 F test/walbak.test f6fde9a5f59d0c697cb1f4af7876178c2f69a7ba
 F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1
 F test/walhook.test 287a69d662939604f2e0452dace2cec8ef634d5e
 F test/walmode.test 40119078da084e6a7403ba57485d5a86ee0e2646
 F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2
-F test/walthread.test 8fdce1721bf01e88a1f83a93ce7ae2e7668bcb26
+F test/walthread.test c9c3b5d19eeb4968254d93f61a7ccd6e8b63f554
 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 da229e44bd4a5d512261da05958d560808c9889f
-R f40b5481d2db02fd1a8b59b3cbe35412
+P 9e891e7543ea4d7dee76deb2456af940f4cac49b
+R 1d9b135e5479cce531b0c9f4c717d59a
 U dan
-Z 9a86a68774ea80363d82258dc9f803a1
+Z f79bb92cf1fa704536cc5c5230dfad45
index cfa4e1552051f362dae5fbc1cba73498711e3c6b..8d47b72c97fdc6bef168ce5177251645205271c1 100644 (file)
@@ -1 +1 @@
-9e891e7543ea4d7dee76deb2456af940f4cac49b
\ No newline at end of file
+d1cadeed4eea20d8892726cc8c69f4f3f57d0cd4
\ No newline at end of file
index c7478d0e825c8aceb79b8d35faf6ffc9bd2f49ae..8a8f4043d16f71d913b7a2abd5918f1582946f72 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -1880,6 +1880,7 @@ int sqlite3WalCheckpoint(
   void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
 ){
   int rc;                         /* Return code */
+  int isChanged = 0;              /* True if a new wal-index header is loaded */
 
   assert( !pLog->isLocked );
 
@@ -1899,10 +1900,19 @@ int sqlite3WalCheckpoint(
   }
 
   /* Copy data from the log to the database file. */
-  rc = logSummaryReadHdr(pLog, 0);
+  rc = logSummaryReadHdr(pLog, &isChanged);
   if( rc==SQLITE_OK ){
     rc = logCheckpoint(pLog, pFd, sync_flags, zBuf);
   }
+  if( isChanged ){
+    /* If a new wal-index header was loaded before the checkpoint was 
+    ** performed, then the pager-cache associated with log pLog is now
+    ** out of date. So zero the cached wal-index header to ensure that
+    ** next time the pager opens a snapshot on this database it knows that
+    ** the cache needs to be reset.
+    */
+    memset(&pLog->hdr, 0, sizeof(LogSummaryHdr));
+  }
 
   /* Release the locks. */
   logLockRegion(pLog, LOG_REGION_A|LOG_REGION_B|LOG_REGION_C, LOG_UNLOCK);
index ca4d606d23b4583a0c8b8e6c9704f99fbe269f81..7b79d0e232f9c5aa4eeba0ef862dd7320171d188 100644 (file)
@@ -918,5 +918,50 @@ foreach code [list {
   db close
 }
 
+#-------------------------------------------------------------------------
+# Check a fun corruption case has been fixed.
+#
+# The problem was that after performing a checkpoint using a connection
+# that had an out-of-date pager-cache, the next time the connection was
+# used it did not realize the cache was out-of-date and proceeded to
+# operate with an inconsistent cache. Leading to corruption.
+#
+
+catch { db close }
+catch { db2 close }
+catch { db3 close }
+file delete -force test.db test.db-wal
+sqlite3 db test.db
+sqlite3 db2 test.db
+
+do_test wal-14 {
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE t1(a PRIMARY KEY, b);
+    INSERT INTO t1 VALUES(randomblob(10), randomblob(100));
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
+  }
+
+  db2 eval { 
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100);
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100);
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100);
+    INSERT INTO t1 SELECT randomblob(10), randomblob(100);
+  }
+
+  # After executing the "PRAGMA checkpoint", connection [db] was being
+  # left with an inconsistent cache. Running the CREATE INDEX statement
+  # in this state led to database corruption.
+  catchsql { 
+    PRAGMA checkpoint;
+    CREATE INDEX i1 on t1(b);
+  }
+   
+  db2 eval { PRAGMA integrity_check }
+} {ok}
+
+
 finish_test
 
index 353b7e42ddf6d5fafad27d45b8c6769687fb7af0..efd321df3b4da18f42f2dfba1c544ff2efab6dea 100644 (file)
@@ -24,9 +24,10 @@ 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.
 #
-set seconds(walthread-1)  0
-set seconds(walthread-2)  0
+set seconds(walthread-1) 20
+set seconds(walthread-2) 20
 set seconds(walthread-3) 20
+set seconds(walthread-4) 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.
@@ -373,7 +374,7 @@ do_thread_test2 walthread-2 -seconds $seconds(walthread-2) -init {
   set {} "[expr $nRun-$nDel] w, $nDel r"
 }
 
-do_thread_test2 walthread-3 -seconds $seconds(walthread-3) -init {
+do_thread_test walthread-3 -seconds $seconds(walthread-3) -init {
   execsql {
     PRAGMA journal_mode = WAL;
     CREATE TABLE t1(cnt PRIMARY KEY, sum1, sum2);
@@ -425,5 +426,33 @@ do_thread_test2 walthread-3 -seconds $seconds(walthread-3) -init {
   }
 }
 
+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.
+  db busy {}
+  while {[tt_continue]} integrity_check
+  set {} ok
+} -thread w 1 {
+
+  proc wal_hook {zDb nEntry} {
+    if {$nEntry>15} { return 1 }
+    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
+}
+
 finish_test