From: drh Date: Wed, 3 Jan 2007 15:34:29 +0000 (+0000) Subject: Make sure that the database size cache in the pager is invalidated whenever X-Git-Tag: version-3.6.10~2620 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1aa2d8b55bffb70e7286acc74a8a6b2018d7e63f;p=thirdparty%2Fsqlite.git Make sure that the database size cache in the pager is invalidated whenever the database is unlocked. A stale value in the database size cache can result in database corruption on a heavily loaded system running autovacuum. (CVS 3548) FossilOrigin-Name: 6806b9ecb5e3b90e793c5862404e76485df33b25 --- diff --git a/manifest b/manifest index b57f798cff..25ee259b46 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\svtab_err\stest\sto\scheck\sfor\s-DSQLITE_MEMDEBUG=1\sand\sskip\sthe\stests\nif\smissing.\s\sPager\sis\smore\scareful\sto\sclear\sits\sfile\ssize\scache.\s\sRemove\nan\sassert()\sin\sVDBE\sthat\smight\sfail\son\sa\scorrupt\sdatabase\sfile.\s(CVS\s3547) -D 2007-01-02T18:41:55 +C Make\ssure\sthat\sthe\sdatabase\ssize\scache\sin\sthe\spager\sis\sinvalidated\swhenever\nthe\sdatabase\sis\sunlocked.\s\sA\sstale\svalue\sin\sthe\sdatabase\ssize\scache\scan\nresult\sin\sdatabase\scorruption\son\sa\sheavily\sloaded\ssystem\srunning\nautovacuum.\s(CVS\s3548) +D 2007-01-03T15:34:30 F Makefile.in 63a71177ed4355c829229affe11167bd28c85884 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -85,7 +85,7 @@ F src/os_unix.c d4bc8cbe1c0dc330bd55bf7821db5b7dbfbf183e F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c ca46001d4ec446885f72d3b7fd6a657136156228 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 5a153277b050b4fe9db3e3ced6b3a7ad7f19561e +F src/pager.c 4dbd6a12eb43f10a3c870a3006a54a7756768455 F src/pager.h 2e6d42f4ae004ae748a037b8468112b851c447a7 F src/parse.y 2f571c5f6219428d7fb08737db3d113742b1cceb F src/pragma.c d0891d3504b6291b506a5ec2226bbf79ffcef003 @@ -423,7 +423,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 720189b8fafa61e5b712b409e76c368079b4bf96 -R a594a599c63c21c9d19504b49bbf2e77 +P bf1afd016ad71dac90e58540122108f92e77ce3d +R ffed07664ab99ec35d86454afb31b5e4 U drh -Z 4cc2942b88b80ed65e59fb32451d8d19 +Z 6c9f735d21716c225946d83bfcb229d4 diff --git a/manifest.uuid b/manifest.uuid index bf6c1e52fc..a7467853d2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bf1afd016ad71dac90e58540122108f92e77ce3d \ No newline at end of file +6806b9ecb5e3b90e793c5862404e76485df33b25 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 9c36c01e19..b6fe7f3789 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.278 2007/01/02 18:41:55 drh Exp $ +** @(#) $Id: pager.c,v 1.279 2007/01/03 15:34:30 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -850,6 +850,22 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ return p; } +/* +** Unlock the database file. +** +** Once all locks have been removed from the database file, other +** processes or threads might change the file. So make sure all of +** our internal cache is invalidated. +*/ +static void pager_unlock(Pager *pPager){ + if( !MEMDB ){ + sqlite3OsUnlock(pPager->fd, NO_LOCK); + pPager->dbSize = -1; + } + pPager->state = PAGER_UNLOCK; +} + + /* ** Unlock the database and clear the in-memory cache. This routine ** sets the state of the pager back to what it was when it was first @@ -874,9 +890,7 @@ static void pager_reset(Pager *pPager){ if( pPager->state>=PAGER_RESERVED ){ sqlite3pager_rollback(pPager); } - sqlite3OsUnlock(pPager->fd, NO_LOCK); - pPager->state = PAGER_UNLOCK; - pPager->dbSize = -1; + pager_unlock(pPager); pPager->nRef = 0; assert( pPager->journalOpen==0 ); } @@ -1425,6 +1439,7 @@ static int pager_stmt_playback(Pager *pPager){ if( pPager->state>=PAGER_EXCLUSIVE ){ rc = pager_truncate(pPager, pPager->stmtSize); } + assert( pPager->state>=PAGER_SHARED ); pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. @@ -1974,9 +1989,15 @@ static void memoryTruncate(Pager *pPager){ */ static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; + + /* The OS lock values must be the same as the Pager lock values */ assert( PAGER_SHARED==SHARED_LOCK ); assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); + + /* If the file is currently unlocked then the size must be unknown */ + assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB ); + if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ @@ -1995,6 +2016,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ */ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ int rc; + assert( pPager->state>=PAGER_SHARED || MEMDB ); sqlite3pager_pagecount(pPager); if( pPager->errCode ){ rc = pPager->errCode; @@ -2064,16 +2086,12 @@ int sqlite3pager_close(Pager *pPager){ disable_simulated_io_errors(); sqlite3pager_rollback(pPager); enable_simulated_io_errors(); - if( !MEMDB ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - } + pager_unlock(pPager); assert( pPager->errCode || pPager->journalOpen==0 ); break; } case PAGER_SHARED: { - if( !MEMDB ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - } + pager_unlock(pPager); break; } default: { @@ -2674,8 +2692,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){ */ rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - pPager->state = PAGER_UNLOCK; + pager_unlock(pPager); return pager_error(pPager, rc); } pPager->state = PAGER_EXCLUSIVE; @@ -2690,8 +2707,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){ */ rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd); if( rc!=SQLITE_OK ){ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - pPager->state = PAGER_UNLOCK; + pager_unlock(pPager); return SQLITE_BUSY; } pPager->journalOpen = 1; @@ -2973,8 +2989,7 @@ failed_to_open_journal: */ sqlite3OsDelete(pPager->zJournal); }else{ - sqlite3OsUnlock(pPager->fd, NO_LOCK); - pPager->state = PAGER_UNLOCK; + pager_unlock(pPager); } return rc; } @@ -3233,6 +3248,7 @@ int sqlite3pager_write(void *pData){ /* Update the database size and return. */ + assert( pPager->state>=PAGER_SHARED ); if( pPager->dbSize<(int)pPg->pgno ){ pPager->dbSize = pPg->pgno; if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){ @@ -3308,6 +3324,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){ assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */ pPg->alwaysRollback = 1; if( pPg->dirty && !pPager->stmtInUse ){ + assert( pPager->state>=PAGER_SHARED ); if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSizedbSize ){ /* If this pages is the last page in the file and the file has grown ** during the current transaction, then do NOT mark the page as clean. @@ -3544,6 +3561,7 @@ int sqlite3pager_stmt_begin(Pager *pPager){ int rc; char zTemp[SQLITE_TEMPNAME_SIZE]; assert( !pPager->stmtInUse ); + assert( pPager->state>=PAGER_SHARED ); assert( pPager->dbSize>=0 ); TRACE2("STMT-BEGIN %d\n", PAGERID(pPager)); if( MEMDB ){