Fix a but in the WAL checkpoint code causing SQLite to use an inconsistent cache in a subsequent transaction.

FossilOrigin-Name: d1cadeed4eea20d8892726cc8c69f4f3f57d0cd4
This commit is contained in:
dan 2010-04-29 14:51:33 +00:00
parent b4e3a6f72f
commit 31c03907fd
5 changed files with 97 additions and 13 deletions

View File

@ -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

View File

@ -1 +1 @@
9e891e7543ea4d7dee76deb2456af940f4cac49b
d1cadeed4eea20d8892726cc8c69f4f3f57d0cd4

View File

@ -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);

View 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

View 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