From: dan Date: Tue, 3 Aug 2010 15:57:09 +0000 (+0000) Subject: Add comments to clarify the purpose of the pager "error state". X-Git-Tag: version-3.7.2~53^2~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b22aa4a63de7874a9eb898f3497f8a47d9455774;p=thirdparty%2Fsqlite.git Add comments to clarify the purpose of the pager "error state". FossilOrigin-Name: fde4c59782e98366792e1552fd122e7d80a277ff --- diff --git a/manifest b/manifest index b67585edd7..736464b9c6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sstate\sdiagram\sto\scomments\sin\sexperimental\sversion\sof\spager.c. -D 2010-08-03T12:48:46 +C Add\scomments\sto\sclarify\sthe\spurpose\sof\sthe\spager\s"error\sstate". +D 2010-08-03T15:57:10 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e F src/os_unix.c ae5ca8a6031380708f3fec7be325233d49944914 F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7 -F src/pager.c 24f978063ff3f18f1632b05b695717cc9818538a +F src/pager.c 809f4dfbca43fd64ef27855e193d8544a5054668 F src/pager.h 80726162dc3942f59ab27b738fb667b9ba0a89d5 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 @@ -841,7 +841,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 0a636798bdb6961a47327091715b254f79add823 -R b916884b782901df5d25760d516d1243 +P 16dcf5a6d3ebff9a734705693b5ac740f4ff2cc1 +R f5f08ae2bf16feac4ddffb2e7526923b U dan -Z a547af01cff05efb8820775070ecaafe +Z 158c2b787243a4910abe77703b2eb315 diff --git a/manifest.uuid b/manifest.uuid index 34229d28a1..c2bab4d837 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -16dcf5a6d3ebff9a734705693b5ac740f4ff2cc1 \ No newline at end of file +fde4c59782e98366792e1552fd122e7d80a277ff \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 100f4e90c9..1129021e91 100644 --- a/src/pager.c +++ b/src/pager.c @@ -140,6 +140,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted. ** ** READER: +** ** In this state all the requirements for reading the database in ** rollback (non-WAL) mode are met. Unless the pager is (or recently ** was) in exclusive-locking mode, a user-level read transaction is @@ -152,12 +153,16 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** may not be trusted at this point. ** ** WRITER_INITIAL: +** ** * A write transaction is active. ** * A RESERVED or greater lock is held on the database file. ** * The dbSize, dbOrigSize and dbFileSize variables are all valid. ** * The contents of the pager cache have not been modified. +** * The journal file may or may not be open. +** * Nothing (not even the first header) has been written to the journal. ** ** WRITER_CACHEMOD: +** ** * A write transaction is active. ** * A RESERVED or greater lock is held on the database file. ** * The journal file is open and the first header has been written @@ -165,6 +170,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** * The contents of the page cache have been modified. ** ** WRITER_DBMOD: +** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * The journal file is open and the first header has been written @@ -173,6 +179,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** written to disk). ** ** WRITER_FINISHED: +** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * All writing and syncing of journal and database data has finished. @@ -180,12 +187,62 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** commit the transaction. If an error did occur, the caller will need ** to rollback the transaction. ** +** ERROR: +** +** The ERROR state is entered when an IO, OOM or disk-full error +** occurs at a point in the code that makes it difficult to be sure +** that the in-memory pager state (cache contents, db size etc.) are +** consistent with the contents of the file-system. +** +** For example, if an IO error occurs while performing a rollback, +** the contents of the page-cache may be left in an inconsistent state. +** At this point it would be dangerous to change back to READER state +** (as usually happens after a rollback). Any subsequent readers might +** report database corruption (due to the inconsistent cache), and if +** they upgrade to writers, they may inadvertently corrupt the database +** file. To avoid this hazard, the pager switches into the ERROR state +** instead of READER following such an error. +** +** Once it has entered the ERROR state, any attempt to use the pager +** to read or write data returns an error. Eventually, once all +** outstanding transactions have been abandoned, the pager is able to +** transition back to NONE state, discarding the contents of the +** page-cache and any other in-memory state at the same time. Everything +** is reloaded from disk (and, if necessary, hot-journal rollback peformed) +** when a read-transaction is next opened on the pager (transitioning +** the pager into READER state). At that point the system has recovered +** from the error. +** +** Specifically, the pager jumps into the ERROR state if: +** +** 1. An error occurs while attempting a rollback. This happens in +** function sqlite3PagerRollback(). +** +** 2. An error occurs while attempting to finalize a journal file +** following a commit in function sqlite3PagerCommitPhaseTwo(). +** +** 3. An error occurs while attempting to write to the journal or +** database file in function pagerStress() in order to free up +** memory. +** +** In other cases, the error is returned to the b-tree layer. The b-tree +** layer then attempts a rollback operation. If the error condition +** persists, the pager enters the ERROR state via condition (1) above. +** +** Condition (3) is necessary because it can be triggered by a read-only +** statement executed within a transaction. In this case, if the error +** code were simply returned to the user, the b-tree layer would not +** automatically attempt a rollback, as it assumes that an error in a +** read-only statement cannot leave the pager in an internally inconsistent +** state. +** +** ** State diagram: ** -** NONE <-------------+ -** | | -** V | -** +---------> READER------------->| +** NONE <------+------+ +** | | | +** V | | +** +---------> READER-------+ | ** | | | ** | V | ** |<-------WRITER_INITIAL-----> ERROR @@ -1619,7 +1676,6 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ rc = zeroJournalHdr(pPager, hasMaster); - pager_error(pPager, rc); pPager->journalOff = 0; }else{ /* This branch may be executed with Pager.journalMode==MEMORY if @@ -4327,7 +4383,7 @@ int sqlite3PagerSharedLock(Pager *pPager){ rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ assert( pPager->eLock==PAGER_UNLOCK ); - return pager_error(pPager, rc); + goto failed; } } @@ -4358,7 +4414,6 @@ int sqlite3PagerSharedLock(Pager *pPager){ */ rc = pagerLock(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ - rc = pager_error(pPager, rc); goto failed; } @@ -4411,6 +4466,10 @@ int sqlite3PagerSharedLock(Pager *pPager){ ** it back since the process that crashed and left the hot journal ** probably did not sync it and we are required to always sync ** the journal before playing it back. + ** + ** Even if an error occurs while syncing or rolling back the + ** hot-journal, there is no need to enter the ERROR state here, as + ** the pager never left state NONE anyhow. */ if( isOpen(pPager->jfd) ){ rc = pagerSyncHotJournal(pPager); @@ -4420,7 +4479,6 @@ int sqlite3PagerSharedLock(Pager *pPager){ pPager->eState = PAGER_NONE; } if( rc!=SQLITE_OK ){ - rc = pager_error(pPager, rc); goto failed; } }else{ @@ -4488,8 +4546,10 @@ int sqlite3PagerSharedLock(Pager *pPager){ failed: if( rc!=SQLITE_OK ){ - /* pager_unlock() is a no-op for exclusive mode and in-memory databases. */ pager_unlock(pPager); + assert( (pPager->eState==PAGER_NONE) + || (pPager->exclusiveMode && pagerUseWal(pPager)) + ); }else{ pPager->eState = PAGER_READER; } @@ -5544,21 +5604,12 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ ** called, just return the same error code without doing anything. */ if( NEVER(pPager->errCode) ) return pPager->errCode; - /* This function should not be called if the pager is not in at least - ** PAGER_RESERVED state. **FIXME**: Make it so that this test always - ** fails - make it so that we never reach this point if we do not hold - ** all necessary locks. - */ assert( pPager->eState==PAGER_WRITER_INITIAL || pPager->eState==PAGER_WRITER_FINISHED || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD) ); assert( assert_pager_state(pPager) ); -#if 0 - if( NEVER(pPager->statesetMaster); if( rc==SQLITE_OK ) rc = rc2; - rc = pager_error(pPager, rc); }else if( pPager->eState==PAGER_WRITER_INITIAL ){ - rc = pager_end_transaction(pPager, pPager->setMaster); + rc = pager_end_transaction(pPager, 0); }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ if( pPager->eState>=PAGER_WRITER_DBMOD ){ pager_playback(pPager, 0); @@ -5660,14 +5709,12 @@ int sqlite3PagerRollback(Pager *pPager){ }else{ rc = pager_playback(pPager, 0); } - - /* If an error occurs during a ROLLBACK, we can no longer trust the pager - ** cache. So call pager_error() on the way out to make any error - ** persistent. - */ - rc = pager_error(pPager, rc); } - return rc; + + /* If an error occurs during a ROLLBACK, we can no longer trust the pager + ** cache. So call pager_error() on the way out to make any error persistent. + */ + return pager_error(pPager, rc); } /*