From b7d53f54ae81f6d0bc73d887591d57a3ae8f090e Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 6 May 2010 17:28:08 +0000 Subject: [PATCH] Fix a bug whereby an old snapshot could be checkpointed (and subsequent transactions discarded) if the last connection to disconnect from a WAL database happended to be holding an out-of-date wal-index header. FossilOrigin-Name: d0c0034b0baa83046c1d6b94c886f7039e4e06f5 --- manifest | 26 +++++++---------------- manifest.uuid | 2 +- src/wal.c | 15 ++++++++++++- test/wal.test | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 6117c1d3c8..141661dbc0 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,5 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA1 - -C After\sthrowing\san\serror\sto\ssay\sthat\sone\scannot\schange\sinto\sWAL\smode\swithin\na\stranactions,\sdo\snot\sthen\sgo\sand\schange\sinto\sWAL\smode. -D 2010-05-06T16:06:38 +C Fix\sa\sbug\swhereby\san\sold\ssnapshot\scould\sbe\scheckpointed\s(and\ssubsequent\stransactions\sdiscarded)\sif\sthe\slast\sconnection\sto\sdisconnect\sfrom\sa\sWAL\sdatabase\shappended\sto\sbe\sholding\san\sout-of-date\swal-index\sheader. +D 2010-05-06T17:28:09 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -227,7 +224,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 d152a78f6c98418bf3ebd9edc24cf23bc6f6e866 +F src/wal.c d7250e0da0d389d9fc3839363570f3f74da0b60d F src/wal.h b4c42014b5fa3b4e6244ac8c65de7ff67adeb27c F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356 @@ -764,7 +761,7 @@ 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 7dda3fc1637aa035510199e166941bfe987846ba +F test/wal.test f0b78497bbe2e7f3c35a1c28e9772fe0dead1fc8 F test/wal2.test 4a8e20416020f83b792464edee18107321dea99a F test/walbak.test a0e45187c7d8928df035dfea29b99b016b21ca3c F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f @@ -816,14 +813,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 98a9713e0030a36ea99a18a12a2e7685c6db72b3 -R a6a5701c6d4007c6249db0d97b38d4b9 -U drh -Z 5088fc0f8b2c64d8a5a9201858770842 ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.6 (GNU/Linux) - -iD8DBQFL4ukRoxKgR168RlERAl8bAJ9p5VPkPYSbXCDjRN/Gx6UcnU6HcgCfcazb -/vpPlHetvENT53KXSL9Rsh0= -=ElgJ ------END PGP SIGNATURE----- +P 56a17dae91600a3863903f8d654ed52a0f720caf +R aee4f4f487984caf56f9844933d88af1 +U dan +Z 2489bba830e3043eba5db422e0f13170 diff --git a/manifest.uuid b/manifest.uuid index 2b4b8bb22f..5e774690ae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -56a17dae91600a3863903f8d654ed52a0f720caf \ No newline at end of file +d0c0034b0baa83046c1d6b94c886f7039e4e06f5 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index 4bbf7960ce..9aa629729e 100644 --- a/src/wal.c +++ b/src/wal.c @@ -370,6 +370,19 @@ static int walIndexEntry(u32 iFrame){ ); } +/* +** Return the minimum mapping size in bytes that can be used to read the +** wal-index up to and including frame iFrame. If iFrame is the last frame +** in a block of 256 frames, the returned byte-count includes the space +** required by the 256-byte index block. +*/ +static int walMappingSize(u32 iFrame){ + return ( WALINDEX_LOCK_OFFSET + WALINDEX_LOCK_RESERVED + + iFrame*sizeof(u32) + + (iFrame>>8)*256 + ); +} + /* ** Release our reference to the wal-index memory map, if we are holding ** it. @@ -835,7 +848,7 @@ int sqlite3WalClose( */ rc = sqlite3OsLock(pFd, SQLITE_LOCK_EXCLUSIVE); if( rc==SQLITE_OK ){ - rc = walCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf); + rc = sqlite3WalCheckpoint(pWal, pFd, sync_flags, nBuf, zBuf, 0, 0); if( rc==SQLITE_OK ){ isDelete = 1; } diff --git a/test/wal.test b/test/wal.test index 01a5ee3fb0..50c2ca1aa2 100644 --- a/test/wal.test +++ b/test/wal.test @@ -276,6 +276,20 @@ do_test wal-4.5.7 { } {ok} db2 close +do_test wal-4.6.1 { + execsql { + DELETE FROM t2; + PRAGMA wal_checkpoint; + BEGIN; + INSERT INTO t2 VALUES('w', 'x'); + SAVEPOINT save; + INSERT INTO t2 VALUES('y', 'z'); + ROLLBACK TO save; + COMMIT; + SELECT * FROM t2; + } +} {w x} + reopen_db do_test wal-5.1 { @@ -1340,7 +1354,52 @@ foreach {tn pgsz works} { } } +#------------------------------------------------------------------------- +# The following test - wal-19.* - fixes a bug that was present during +# development. +# +# When a database connection in WAL mode is closed, it attempts an +# EXCLUSIVE lock on the database file. If the lock is obtained, the +# connection knows that it is the last connection to disconnect from +# the database, so it runs a checkpoint operation. The bug was that +# the connection was not updating its private copy of the wal-index +# header before doing so, meaning that it could checkpoint an old +# snapshot. +# +do_test wal-19.1 { + file delete -force test.db test.db-wal test.db-journal + sqlite3 db test.db + sqlite3 db2 test.db + execsql { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); + } + execsql { SELECT * FROM t1 } db2 +} {1 2 3 4} +do_test wal-19.2 { + execsql { + INSERT INTO t1 VALUES(5, 6); + SELECT * FROM t1; + } +} {1 2 3 4 5 6} +do_test wal-19.3 { + db close + db2 close + file exists test.db-wal +} {0} +do_test wal-19.4 { + # When the bug was present, the following was returning {1 2 3 4} only, + # as [db2] had an out-of-date copy of the wal-index header when it was + # closed. + # + sqlite3 db test.db + execsql { SELECT * FROM t1 } +} {1 2 3 4 5 6} + catch { db2 close } catch { db close } + finish_test -- 2.47.2