From a927e94e7186679abbe0404ee167b923ddd507ad Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 24 Jun 2010 02:46:48 +0000 Subject: [PATCH] Make sure the wal-index reader detects an incorrect version number even if it had to hold a lock in order to read the wal-index. Also, expand and enhance various comments in wal.c. FossilOrigin-Name: 2e6a462cebc05bfd4648d26dd5ae70b68844aa5f --- manifest | 18 +++++++-------- manifest.uuid | 2 +- src/wal.c | 63 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 3396c68a2c..53818fe472 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C Fix\sand/or\simprove\scomments\sin\swal.c.\s\sNo\scode\schanges. -D 2010-06-23T22:00:36 +C Make\ssure\sthe\swal-index\sreader\sdetects\san\sincorrect\sversion\snumber\seven\sif\nit\shad\sto\shold\sa\slock\sin\sorder\sto\sread\sthe\swal-index.\s\sAlso,\sexpand\sand\senhance\nvarious\scomments\sin\swal.c. +D 2010-06-24T02:46:49 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -229,7 +229,7 @@ F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256 F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda -F src/wal.c 51b5d2259d86a26125007d3d788da5a2a2715b1a +F src/wal.c 40e6d0acde18a0d4796310db4d6382a12340388c F src/wal.h 4ace25262452d17e7d3ec970c89ee17794004008 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c 1c895bef33d0dfc7ed90fb1f74120435d210ea56 @@ -828,14 +828,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 3e9680c4c18140d083b24e05a21ea6792aef2487 -R 128d792d7f9b9a40582f4d46c120cca4 +P ee9991be082202c6637adb47affc777e7917be04 +R df56ab9f7222776abd3e8b42ef209701 U drh -Z 369983deae2c52862083f493477e4ceb +Z 85f62e57e9c5554f99cfd3649411a9ff -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFMIoQHoxKgR168RlERAkTMAJ4y6IEC74XLF+DMxIuBS7Lmcv3IqQCeJXdd -wPN5UVQx6y4hhnn2sGwnj/w= -=O5UN +iD8DBQFMIscdoxKgR168RlERAh1nAJ47gefagsKL4XohGBiiEgmsbUY6vgCfcfRz +mTG8eTaypLtEv2BjR4hvPQw= +=bshK -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index cd54b0bdbc..008fb60dc4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ee9991be082202c6637adb47affc777e7917be04 \ No newline at end of file +2e6a462cebc05bfd4648d26dd5ae70b68844aa5f \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index bbd2546eb5..3f976329f6 100644 --- a/src/wal.c +++ b/src/wal.c @@ -1663,26 +1663,20 @@ int walIndexTryHdr(Wal *pWal, int *pChanged){ /* ** Read the wal-index header from the wal-index and into pWal->hdr. -** If the wal-header appears to be corrupt, try to recover the log -** before returning. +** If the wal-header appears to be corrupt, try to reconstruct the +** wal-index from the WAL before returning. ** ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is ** changed by this opertion. If pWal->hdr is unchanged, set *pChanged ** to 0. ** -** This routine also maps the wal-index content into memory and assigns -** ownership of that mapping to the current thread. In some implementations, -** only one thread at a time can hold a mapping of the wal-index. Hence, -** the caller should strive to invoke walIndexUnmap() as soon as possible -** after this routine returns. -** ** If the wal-index header is successfully read, return SQLITE_OK. ** Otherwise an SQLite error code. */ static int walIndexReadHdr(Wal *pWal, int *pChanged){ int rc; /* Return code */ int badHdr; /* True if a header read failed */ - volatile u32 *page0; + volatile u32 *page0; /* Chunk of wal-index containing header */ /* Ensure that page 0 of the wal-index (the page that contains the ** wal-index header) is mapped. Return early if an error occurs here. @@ -1697,12 +1691,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ /* If the first page of the wal-index has been mapped, try to read the ** wal-index header immediately, without holding any lock. This usually ** works, but may fail if the wal-index header is corrupt or currently - ** being modified by another user. + ** being modified by another thread or process. */ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); - if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){ - rc = SQLITE_CANTOPEN_BKPT; - } /* If the first attempt failed, it might have been due to a race ** with a writer. So get a WRITE lock and try again. @@ -1725,6 +1716,14 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } + /* If the header is read successfully, check the version number to make + ** sure the wal-index was not constructed with some future format that + ** this version of SQLite cannot understand. + */ + if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){ + rc = SQLITE_CANTOPEN_BKPT; + } + return rc; } @@ -1739,10 +1738,30 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** other transient condition. When that happens, it returns WAL_RETRY to ** indicate to the caller that it is safe to retry immediately. ** -** On success return SQLITE_OK. On a permantent failure (such an +** On success return SQLITE_OK. On a permanent failure (such an ** I/O error or an SQLITE_BUSY because another process is running ** recovery) return a positive error code. ** +** The useWal parameter is true to force the use of the WAL and disable +** the case where the WAL is bypassed because it has been completely +** checkpointed. If useWal==0 then this routine calls walIndexReadHdr() +** to make a copy of the wal-index header into pWal->hdr. If the +** wal-index header has changed, *pChanged is set to 1 (as an indication +** to the caller that the local paget cache is obsolete and needs to be +** flushed.) When useWal==1, the wal-index header is assumed to already +** be loaded and the pChanged parameter is unused. +** +** The caller must set the cnt parameter to the number of prior calls to +** this routine during the current read attempt that returned WAL_RETRY. +** This routine will start taking more aggressive measures to clear the +** race conditions after multiple WAL_RETRY returns, and after an excessive +** number of errors will ultimately return SQLITE_PROTOCOL. The +** SQLITE_PROTOCOL return indicates that some other process has gone rogue +** and is not honoring the locking protocol. There is a vanishingly small +** chance that SQLITE_PROTOCOL could be returned because of a run of really +** bad luck when there is lots of contention for the wal-index, but that +** possibility is so small that it can be safely neglected, we believe. +** ** On success, this routine obtains a read lock on ** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is ** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1) @@ -1752,6 +1771,8 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0 ** Or if pWal->readLock==0, then the reader will ignore the WAL ** completely and get all content directly from the database file. +** If the useWal parameter is 1 then the WAL will never be ignored and +** this routine will always set pWal->readLock>0 on success. ** When the read transaction is completed, the caller must release the ** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1. ** @@ -1796,9 +1817,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ rc = SQLITE_BUSY_RECOVERY; } } - } - if( rc!=SQLITE_OK ){ - return rc; + if( rc!=SQLITE_OK ){ + return rc; + } } pInfo = walCkptInfo(pWal); @@ -1974,9 +1995,9 @@ int sqlite3WalRead( /* If the "last page" field of the wal-index header snapshot is 0, then ** no data will be read from the wal under any circumstances. Return early - ** in this case to avoid the walIndexMap/Unmap overhead. Likewise, if - ** pWal->readLock==0, then the WAL is ignored by the reader so - ** return early, as if the WAL were empty. + ** in this case as an optimization. Likewise, if pWal->readLock==0, + ** then the WAL is ignored by the reader so return early, as if the + ** WAL were empty. */ if( iLast==0 || pWal->readLock==0 ){ *pInWal = 0; @@ -1987,7 +2008,7 @@ int sqlite3WalRead( ** pgno. Each iteration of the following for() loop searches one ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames). ** - ** This code may run concurrently to the code in walIndexAppend() + ** This code might run concurrently to the code in walIndexAppend() ** that adds entries to the wal-index (and possibly to this hash ** table). This means the value just read from the hash ** slot (aHash[iKey]) may have been added before or after the