1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Further updates to comments in pager.c.

FossilOrigin-Name: 5f4c17a33fd442d66c1bf75af9b21954f6906897
This commit is contained in:
dan
2010-08-06 12:00:27 +00:00
parent dc1106148a
commit de1ae34eed
3 changed files with 219 additions and 149 deletions

View File

@@ -1,5 +1,5 @@
C Modify\stest_journal.c\sto\swork\swith\spre-allocated\sdatabases. C Further\supdates\sto\scomments\sin\spager.c.
D 2010-08-06T09:43:04 D 2010-08-06T12:00:27
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
F src/os_unix.c ae5ca8a6031380708f3fec7be325233d49944914 F src/os_unix.c ae5ca8a6031380708f3fec7be325233d49944914
F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7 F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7
F src/pager.c f8fdab85e2dd0a3a55fc2bf212035f50ffcada13 F src/pager.c 3ac13a537a5a1c3fe8cbb39a52e255a52b8b3c99
F src/pager.h 80726162dc3942f59ab27b738fb667b9ba0a89d5 F src/pager.h 80726162dc3942f59ab27b738fb667b9ba0a89d5
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
@@ -843,7 +843,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 6217b607f0cd60383c6cb4ab0fe9da008f611244 P 4894a5d21044b169f412fef095e689cb8a8575dc
R 14b2ef30676c4e420e673009cd2ed209 R c8de9a7d2c35078aa3e4ea331272cd57
U dan U dan
Z f16fc7fc34cf746cc2538d8ca729728e Z e0fe6da6eb2070e7d54dde6c557a0593

View File

@@ -1 +1 @@
4894a5d21044b169f412fef095e689cb8a8575dc 5f4c17a33fd442d66c1bf75af9b21954f6906897

View File

@@ -130,13 +130,13 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** pager may be in any one of the seven states shown in the following ** pager may be in any one of the seven states shown in the following
** state diagram. ** state diagram.
** **
** NONE <------+------+ ** OPEN <------+------+
** | | | ** | | |
** V | | ** V | |
** +---------> READER-------+ | ** +---------> READER-------+ |
** | | | ** | | |
** | V | ** | V |
** |<-------WRITER_INITIAL-----> ERROR ** |<-------WRITER_LOCKED------> ERROR
** | | ^ ** | | ^
** | V | ** | V |
** |<------WRITER_CACHEMOD-------->| ** |<------WRITER_CACHEMOD-------->|
@@ -150,20 +150,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** **
** List of state transitions and the C [function] that performs each: ** List of state transitions and the C [function] that performs each:
** **
** NONE -> READER [sqlite3PagerSharedLock] ** OPEN -> READER [sqlite3PagerSharedLock]
** READER -> NONE [pager_unlock] ** READER -> OPEN [pager_unlock]
** **
** READER -> WRITER_INITIAL [sqlite3PagerBegin] ** READER -> WRITER_LOCKED [sqlite3PagerBegin]
** WRITER_INITIAL -> WRITER_CACHEMOD [pager_open_journal] ** WRITER_LOCKED -> WRITER_CACHEMOD [pager_open_journal]
** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal] ** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal]
** WRITER_DBMOD -> WRITER_FINISHED [sqlite3PagerCommitPhaseOne] ** WRITER_DBMOD -> WRITER_FINISHED [sqlite3PagerCommitPhaseOne]
** WRITER_*** -> READER [pager_end_transaction] ** WRITER_*** -> READER [pager_end_transaction]
** **
** WRITER_*** -> ERROR [pager_error] ** WRITER_*** -> ERROR [pager_error]
** ERROR -> NONE [pager_unlock] ** ERROR -> OPEN [pager_unlock]
** **
** **
** NONE: ** OPEN:
** **
** The pager starts up in this state. Nothing is guaranteed in this ** The pager starts up in this state. Nothing is guaranteed in this
** state - the file may or may not be locked and the database size is ** state - the file may or may not be locked and the database size is
@@ -182,16 +182,12 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** **
** A connection running with locking_mode=normal enters this state when ** A connection running with locking_mode=normal enters this state when
** it opens a read-transaction on the database and returns to state ** it opens a read-transaction on the database and returns to state
** NONE after the read-transaction is completed. However a connection ** OPEN after the read-transaction is completed. However a connection
** running in locking_mode=exclusive (including temp databases) remains in ** running in locking_mode=exclusive (including temp databases) remains in
** this state even after the read-transaction is closed. The only way ** this state even after the read-transaction is closed. The only way
** a locking_mode=exclusive connection can transition from READER to NONE ** a locking_mode=exclusive connection can transition from READER to OPEN
** is via the ERROR state (see below). ** is via the ERROR state (see below).
** **
** TODO: Maybe WAL connections should behave like locking_mode=exclusive
** connections and remain in READER state even when there is no
** active read transaction.
**
** * A read transaction may be active (but a write-transaction cannot). ** * A read transaction may be active (but a write-transaction cannot).
** * A SHARED or greater lock is held on the database file. ** * A SHARED or greater lock is held on the database file.
** * The dbSize variable may be trusted (even if a user-level read ** * The dbSize variable may be trusted (even if a user-level read
@@ -201,10 +197,23 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** * Even if a read-transaction is not open, it is guaranteed that ** * Even if a read-transaction is not open, it is guaranteed that
** there is no hot-journal in the file-system. ** there is no hot-journal in the file-system.
** **
** WRITER_INITIAL: ** WRITER_LOCKED:
** **
** The pager moves to this state from READER when a write-transaction ** The pager moves to this state from READER when a write-transaction
** is first opened on the database. ** is first opened on the database. In WRITER_LOCKED state, all locks
** required to start a write-transaction are held, but no actual
** modifications to the cache or database have taken place.
**
** In rollback mode, a RESERVED or (if the transaction was opened with
** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when
** moving to this state, but the journal file is not written to or opened
** to in this state. If the transaction is committed or rolled back while
** in WRITER_LOCKED state, all that is required is to unlock the database
** file.
**
** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file.
** If the connection is running with locking_mode=exclusive, an attempt
** is made to obtain an EXCLUSIVE lock on the database file.
** **
** * A write transaction is active. ** * A write transaction is active.
** * If the connection is open in rollback-mode, a RESERVED or greater ** * If the connection is open in rollback-mode, a RESERVED or greater
@@ -219,6 +228,11 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** **
** WRITER_CACHEMOD: ** WRITER_CACHEMOD:
** **
** A pager moves from WRITER_LOCKED state to this state when a page is
** first modified by the upper layer. In rollback mode the journal file
** is opened (if it is not already open) and a header written to the
** start of it. The database file on disk has not been modified.
**
** * A write transaction is active. ** * A write transaction is active.
** * A RESERVED or greater lock is held on the database file. ** * A RESERVED or greater lock is held on the database file.
** * The journal file is open and the first header has been written ** * The journal file is open and the first header has been written
@@ -262,7 +276,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** Once it has entered the ERROR state, any attempt to use the pager ** Once it has entered the ERROR state, any attempt to use the pager
** to read or write data returns an error. Eventually, once all ** to read or write data returns an error. Eventually, once all
** outstanding transactions have been abandoned, the pager is able to ** outstanding transactions have been abandoned, the pager is able to
** transition back to NONE state, discarding the contents of the ** transition back to OPEN state, discarding the contents of the
** page-cache and any other in-memory state at the same time. Everything ** page-cache and any other in-memory state at the same time. Everything
** is reloaded from disk (and, if necessary, hot-journal rollback peformed) ** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
** when a read-transaction is next opened on the pager (transitioning ** when a read-transaction is next opened on the pager (transitioning
@@ -292,6 +306,10 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** read-only statement cannot leave the pager in an internally inconsistent ** read-only statement cannot leave the pager in an internally inconsistent
** state. ** state.
** **
** * The Pager.errCode variable is set to something other than SQLITE_OK.
** * There are one or more outstanding references to pages (after the
** last reference is dropped the pager should move back to OPEN state).
**
** **
** Notes: ** Notes:
** **
@@ -299,16 +317,16 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** connection is open in WAL mode. A WAL connection is always in one ** connection is open in WAL mode. A WAL connection is always in one
** of the first four states. ** of the first four states.
** **
** * Normally, a connection open in exclusive mode is never in PAGER_NONE ** * Normally, a connection open in exclusive mode is never in PAGER_OPEN
** state. There are two exceptions: immediately after exclusive-mode has ** state. There are two exceptions: immediately after exclusive-mode has
** been turned on (and before any read or write transactions are ** been turned on (and before any read or write transactions are
** executed), and when the pager is leaving the "error state". ** executed), and when the pager is leaving the "error state".
** **
** * See also: assert_pager_state(). ** * See also: assert_pager_state().
*/ */
#define PAGER_NONE 0 #define PAGER_OPEN 0
#define PAGER_READER 1 #define PAGER_READER 1
#define PAGER_WRITER_INITIAL 2 #define PAGER_WRITER_LOCKED 2
#define PAGER_WRITER_CACHEMOD 3 #define PAGER_WRITER_CACHEMOD 3
#define PAGER_WRITER_DBMOD 4 #define PAGER_WRITER_DBMOD 4
#define PAGER_WRITER_FINISHED 5 #define PAGER_WRITER_FINISHED 5
@@ -335,8 +353,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** required, but nothing really goes wrong. ** required, but nothing really goes wrong.
** **
** The exception is when the database file is unlocked as the pager moves ** The exception is when the database file is unlocked as the pager moves
** from ERROR to NONE state. At this point there may be a hot-journal file ** from ERROR to OPEN state. At this point there may be a hot-journal file
** in the file-system that needs to be rolled back (as part of a NONE->SHARED ** in the file-system that needs to be rolled back (as part of a OPEN->SHARED
** transition, by the same pager or any other). If the call to xUnlock() ** transition, by the same pager or any other). If the call to xUnlock()
** fails at this point and the pager is left holding an EXCLUSIVE lock, this ** fails at this point and the pager is left holding an EXCLUSIVE lock, this
** can confuse the call to xCheckReservedLock() call made later as part ** can confuse the call to xCheckReservedLock() call made later as part
@@ -353,14 +371,14 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** To work around this, if a call to xUnlock() fails when unlocking the ** To work around this, if a call to xUnlock() fails when unlocking the
** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It ** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It
** is only changed back to a real locking state after a successful call ** is only changed back to a real locking state after a successful call
** to xLock(EXCLUSIVE). Also, the code to do the NONE->SHARED state transition ** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition
** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK ** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE ** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE
** lock on the database file before attempting to roll it back. See function ** lock on the database file before attempting to roll it back. See function
** PagerSharedLock() for more detail. ** PagerSharedLock() for more detail.
** **
** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in ** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
** PAGER_NONE state. ** PAGER_OPEN state.
*/ */
#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
@@ -412,27 +430,28 @@ struct PagerSavepoint {
}; };
/* /*
** A open page cache is an instance of the following structure. ** A open page cache is an instance of struct Pager. A description of
** some of the more important member variables follows:
** **
** errCode ** eState
** The Pager.errCode variable is only ever non-zero when the condition
** (Pager.eState==PAGER_ERROR) is true.
** **
** Pager.errCode may be set to SQLITE_FULL, SQLITE_IOERR or one of the ** The current 'state' of the pager object. See the comment and state
** SQLITE_IOERR_XXX sub-codes. ** diagram above for a description of the pager state.
** **
** dbSize, dbOrigSize, dbFileSize ** eLock
** **
** Managing the size of the database file in pages is a little complicated. ** For a real on-disk database, the current lock held on the database file -
** The variable Pager.dbSize contains the number of pages that the database ** NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
** image currently contains. As the database image grows or shrinks this **
** variable is updated. The variable Pager.dbFileSize contains the number ** For a temporary or in-memory database (neither of which require any
** of pages in the database file. This may be different from Pager.dbSize ** locks), this variable is always set to EXCLUSIVE_LOCK. Since such
** if some pages have been appended to the database image but not yet written ** databases always have Pager.exclusiveMode==1, this tricks the pager
** out from the cache to the actual file on disk. Or if the image has been ** logic into thinking that it already has all the locks it will ever
** truncated by an incremental-vacuum operation. The Pager.dbOrigSize variable ** need (and no reason to release them).
** contains the number of pages in the database image when the current **
** transaction was opened. ** In some (obscure) circumstances, this variable may also be set to
** UNKNOWN_LOCK. See the comment above the #define of UNKNOWN_LOCK for
** details.
** **
** changeCountDone ** changeCountDone
** **
@@ -451,24 +470,6 @@ struct PagerSavepoint {
** need only update the change-counter once, for the first transaction ** need only update the change-counter once, for the first transaction
** committed. ** committed.
** **
** dbModified
**
** The dbModified flag is set whenever a database page is dirtied.
** It is cleared at the end of each transaction.
**
** It is used when committing or otherwise ending a transaction. If
** the dbModified flag is clear then less work has to be done.
**
** journalStarted
**
** This flag is set during a write-transaction after the first
** journal-header is written and synced to disk.
**
** After this has happened, new pages appended to the database
** do not need the PGHDR_NEED_SYNC flag set, as they do not need
** to wait for a journal sync before they can be written out to
** the database file (see function pager_write()).
**
** setMaster ** setMaster
** **
** When PagerCommitPhaseOne() is called to commit a transaction, it may ** When PagerCommitPhaseOne() is called to commit a transaction, it may
@@ -479,10 +480,10 @@ struct PagerSavepoint {
** the way in which the journal file is finalized after the transaction is ** the way in which the journal file is finalized after the transaction is
** committed or rolled back when running in "journal_mode=PERSIST" mode. ** committed or rolled back when running in "journal_mode=PERSIST" mode.
** If a journal file does not contain a master-journal pointer, it is ** If a journal file does not contain a master-journal pointer, it is
** finalized by overwriting the first journal header with zeroes. If, ** finalized by overwriting the first journal header with zeroes. If
** on the other hand, it does contain a master-journal pointer, the ** it does contain a master-journal pointer the journal file is finalized
** journal file is finalized by truncating it to zero bytes, just as if ** by truncating it to zero bytes, just as if the connection were
** the connection were running in "journal_mode=truncate" mode. ** running in "journal_mode=truncate" mode.
** **
** Journal files that contain master journal pointers cannot be finalized ** Journal files that contain master journal pointers cannot be finalized
** simply by overwriting the first journal-header with zeroes, as the ** simply by overwriting the first journal-header with zeroes, as the
@@ -492,7 +493,7 @@ struct PagerSavepoint {
** The flag is cleared as soon as the journal file is finalized (either ** The flag is cleared as soon as the journal file is finalized (either
** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
** journal file from being successfully finalized, the setMaster flag ** journal file from being successfully finalized, the setMaster flag
** is cleared anyway. ** is cleared anyway (and the pager will move to ERROR state).
** **
** doNotSpill, doNotSyncSpill ** doNotSpill, doNotSyncSpill
** **
@@ -509,6 +510,58 @@ struct PagerSavepoint {
** This is a boolean variable. If true, then any required sub-journal ** This is a boolean variable. If true, then any required sub-journal
** is opened as an in-memory journal file. If false, then in-memory ** is opened as an in-memory journal file. If false, then in-memory
** sub-journals are only used for in-memory pager files. ** sub-journals are only used for in-memory pager files.
**
** This variable is updated by the upper layer each time a new
** write-transaction is opened.
**
** dbSize, dbOrigSize, dbFileSize
**
** Variable dbSize is set to the number of pages in the database file.
** It is valid in PAGER_READER and higher states (all states except for
** OPEN and ERROR).
**
** dbSize is set based on the size of the database file, which may be
** larger than the size of the database (the value stored at offset
** 28 of the database header by the btree). If the size of the file
** is not an integer multiple of the page-size, the value stored in
** dbSize is rounded down (i.e. a 5KB file with 2K page-size has dbSize==2).
** Except, any file that is greater than 0 bytes in size is considered
** to have at least one page. (i.e. a 1KB file with 2K page-size leads
** to dbSize==1).
**
** During a write-transaction, if pages with page-numbers greater than
** dbSize are modified in the cache, dbSize is updated accordingly.
** Similarly, if the database is truncated using PagerTruncateImage(),
** dbSize is updated.
**
** Variables dbOrigSize and dbFileSize are valid in states
** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize
** variable at the start of the transaction. It is used during rollback,
** and to determine whether or not pages need to be journalled before
** being modified.
**
** Throughout a write-transaction, dbFileSize contains the size of
** the file on disk in pages. It is set to a copy of dbSize when the
** write-transaction is first opened, and updated when VFS calls are made
** to write or truncate the database file on disk.
**
** errCode
**
** The Pager.errCode variable is only ever used in PAGER_ERROR state. It
** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
** sub-codes.
**
** If Pager.errCode is set to SQLITE_IOERR or one of its subcodes, then
** this value is immediately returned when ever any sqlite3PagerXXX() method
** that returns an error code is called. If it is set to SQLITE_FULL,
** then it is returned whenever any such sqlite3PagerXXX() method except
** for PagerAcquire() or PagerLookup() is called.
**
** TODO: Review the SQLITE_FULL/PagerAcquire() exception. Is it a good idea?
** If so, are there bugs whereby shared-cache clients can see
** uncommitted data when the pager is in the ERROR state?
**
*/ */
struct Pager { struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */ sqlite3_vfs *pVfs; /* OS functions to use for IO */
@@ -534,7 +587,7 @@ struct Pager {
** other variables in this block are described in the comment directly ** other variables in this block are described in the comment directly
** above this class definition. ** above this class definition.
*/ */
u8 eState; /* Pager state (NONE, READER, WRITER_INITIAL..) */ u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
u8 eLock; /* Current lock held on database file */ u8 eLock; /* Current lock held on database file */
u8 changeCountDone; /* Set after incrementing the change-counter */ u8 changeCountDone; /* Set after incrementing the change-counter */
u8 setMaster; /* True if a m-j name has been written to jrnl */ u8 setMaster; /* True if a m-j name has been written to jrnl */
@@ -696,14 +749,17 @@ static int pagerUseWal(Pager *pPager){
** Usage: ** Usage:
** **
** assert( assert_pager_state(pPager) ); ** assert( assert_pager_state(pPager) );
**
** This function runs many asserts to try to find inconsistencies in
** the internal state of the Pager object.
*/ */
static int assert_pager_state(Pager *p){ static int assert_pager_state(Pager *p){
Pager *pPager = p; Pager *pPager = p;
/* State must be valid. */ /* State must be valid. */
assert( p->eState==PAGER_NONE assert( p->eState==PAGER_OPEN
|| p->eState==PAGER_READER || p->eState==PAGER_READER
|| p->eState==PAGER_WRITER_INITIAL || p->eState==PAGER_WRITER_LOCKED
|| p->eState==PAGER_WRITER_CACHEMOD || p->eState==PAGER_WRITER_CACHEMOD
|| p->eState==PAGER_WRITER_DBMOD || p->eState==PAGER_WRITER_DBMOD
|| p->eState==PAGER_WRITER_FINISHED || p->eState==PAGER_WRITER_FINISHED
@@ -733,7 +789,7 @@ static int assert_pager_state(Pager *p){
assert( p->eLock!=PENDING_LOCK ); assert( p->eLock!=PENDING_LOCK );
switch( p->eState ){ switch( p->eState ){
case PAGER_NONE: case PAGER_OPEN:
assert( !MEMDB ); assert( !MEMDB );
assert( pPager->errCode==SQLITE_OK ); assert( pPager->errCode==SQLITE_OK );
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
@@ -745,7 +801,7 @@ static int assert_pager_state(Pager *p){
assert( p->eLock>=SHARED_LOCK || p->noReadlock ); assert( p->eLock>=SHARED_LOCK || p->noReadlock );
break; break;
case PAGER_WRITER_INITIAL: case PAGER_WRITER_LOCKED:
assert( p->eLock!=UNKNOWN_LOCK ); assert( p->eLock!=UNKNOWN_LOCK );
assert( pPager->errCode==SQLITE_OK ); assert( pPager->errCode==SQLITE_OK );
if( !pagerUseWal(pPager) ){ if( !pagerUseWal(pPager) ){
@@ -798,7 +854,7 @@ static int assert_pager_state(Pager *p){
case PAGER_ERROR: case PAGER_ERROR:
/* There must be at least one outstanding reference to the pager if /* There must be at least one outstanding reference to the pager if
** in ERROR state. Otherwise the pager should have already dropped ** in ERROR state. Otherwise the pager should have already dropped
** back to NONE state. ** back to OPEN state.
*/ */
assert( pPager->errCode!=SQLITE_OK ); assert( pPager->errCode!=SQLITE_OK );
assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
@@ -809,6 +865,11 @@ static int assert_pager_state(Pager *p){
} }
/* /*
** Return a pointer to a human readable string in a static buffer
** containing the state of the Pager object passed as an argument. This
** is intended to be used within debuggers. For example, as an alternative
** to "print *pPager" in gdb:
**
** (gdb) printf "%s", print_pager_state(pPager) ** (gdb) printf "%s", print_pager_state(pPager)
*/ */
static char *print_pager_state(Pager *p){ static char *print_pager_state(Pager *p){
@@ -823,15 +884,15 @@ static char *print_pager_state(Pager *p){
"Backing store: tempFile=%d memDb=%d useJournal=%d\n" "Backing store: tempFile=%d memDb=%d useJournal=%d\n"
"Journal: journalOff=%lld journalHdr=%lld\n" "Journal: journalOff=%lld journalHdr=%lld\n"
, p->zFilename , p->zFilename
, p->eState==PAGER_NONE ? "NONE" : , p->eState==PAGER_OPEN ? "OPEN" :
p->eState==PAGER_READER ? "READER" : p->eState==PAGER_READER ? "READER" :
p->eState==PAGER_WRITER_INITIAL ? "WRITER_INITIAL" : p->eState==PAGER_WRITER_LOCKED ? "WRITER_LOCKED" :
p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" : p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" :
p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" : p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" :
p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" : p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" :
p->eState==PAGER_ERROR ? "ERROR" : "?error?" p->eState==PAGER_ERROR ? "ERROR" : "?error?"
, (int)p->errCode , (int)p->errCode
, p->eLock==NO_LOCK ? "NONE" : , p->eLock==NO_LOCK ? "OPEN" :
p->eLock==RESERVED_LOCK ? "RESERVED" : p->eLock==RESERVED_LOCK ? "RESERVED" :
p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" : p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" :
p->eLock==SHARED_LOCK ? "SHARED" : p->eLock==SHARED_LOCK ? "SHARED" :
@@ -1590,7 +1651,7 @@ static void pager_unlock(Pager *pPager){
if( pagerUseWal(pPager) ){ if( pagerUseWal(pPager) ){
assert( !isOpen(pPager->jfd) ); assert( !isOpen(pPager->jfd) );
sqlite3WalEndReadTransaction(pPager->pWal); sqlite3WalEndReadTransaction(pPager->pWal);
pPager->eState = PAGER_NONE; pPager->eState = PAGER_OPEN;
}else if( !pPager->exclusiveMode ){ }else if( !pPager->exclusiveMode ){
int rc; /* Error code returned by pagerUnlockDb() */ int rc; /* Error code returned by pagerUnlockDb() */
int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0; int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
@@ -1622,24 +1683,24 @@ static void pager_unlock(Pager *pPager){
pPager->eLock = UNKNOWN_LOCK; pPager->eLock = UNKNOWN_LOCK;
} }
/* The pager state may be changed from PAGER_ERROR to PAGER_NONE here /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here
** without clearing the error code. This is intentional - the error ** without clearing the error code. This is intentional - the error
** code is cleared and the cache reset in the block below. ** code is cleared and the cache reset in the block below.
*/ */
assert( pPager->errCode || pPager->eState!=PAGER_ERROR ); assert( pPager->errCode || pPager->eState!=PAGER_ERROR );
pPager->changeCountDone = 0; pPager->changeCountDone = 0;
pPager->eState = PAGER_NONE; pPager->eState = PAGER_OPEN;
} }
/* If Pager.errCode is set, the contents of the pager cache cannot be /* If Pager.errCode is set, the contents of the pager cache cannot be
** trusted. Now that there are no outstanding references to the pager, ** trusted. Now that there are no outstanding references to the pager,
** it can safely move back to PAGER_NONE state. This happens in both ** it can safely move back to PAGER_OPEN state. This happens in both
** normal and exclusive-locking mode. ** normal and exclusive-locking mode.
*/ */
if( pPager->errCode && !MEMDB ){ if( pPager->errCode && !MEMDB ){
pager_reset(pPager); pager_reset(pPager);
pPager->changeCountDone = pPager->tempFile; pPager->changeCountDone = pPager->tempFile;
pPager->eState = PAGER_NONE; pPager->eState = PAGER_OPEN;
pPager->errCode = SQLITE_OK; pPager->errCode = SQLITE_OK;
} }
@@ -1745,7 +1806,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
/* Do nothing if the pager does not have an open write transaction. */ /* Do nothing if the pager does not have an open write transaction. */
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState!=PAGER_ERROR );
if( pPager->eState<PAGER_WRITER_INITIAL && pPager->eLock<RESERVED_LOCK ){ if( pPager->eState<PAGER_WRITER_LOCKED && pPager->eLock<RESERVED_LOCK ){
return SQLITE_OK; return SQLITE_OK;
} }
@@ -1834,9 +1895,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
** call to pager_unlock(), as described above. ** call to pager_unlock(), as described above.
*/ */
static void pagerUnlockAndRollback(Pager *pPager){ static void pagerUnlockAndRollback(Pager *pPager){
if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_NONE ){ if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_OPEN ){
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
if( pPager->eState>=PAGER_WRITER_INITIAL ){ if( pPager->eState>=PAGER_WRITER_LOCKED ){
sqlite3BeginBenignMalloc(); sqlite3BeginBenignMalloc();
sqlite3PagerRollback(pPager); sqlite3PagerRollback(pPager);
sqlite3EndBenignMalloc(); sqlite3EndBenignMalloc();
@@ -1991,7 +2052,7 @@ static int pager_playback_one_page(
return rc; return rc;
} }
assert( pPager->eState>=PAGER_WRITER_CACHEMOD assert( pPager->eState>=PAGER_WRITER_CACHEMOD
|| (pPager->eState==PAGER_NONE && isMainJrnl) || (pPager->eState==PAGER_OPEN && isMainJrnl)
); );
/* When playing back page 1, restore the nReserve setting /* When playing back page 1, restore the nReserve setting
@@ -2048,7 +2109,7 @@ static int pager_playback_one_page(
}else{ }else{
isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC)); isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC));
} }
if( (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_NONE) if( (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
&& isOpen(pPager->fd) && isOpen(pPager->fd)
&& isSynced && isSynced
){ ){
@@ -2300,7 +2361,7 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
assert( pPager->eState!=PAGER_READER ); assert( pPager->eState!=PAGER_READER );
if( isOpen(pPager->fd) if( isOpen(pPager->fd)
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_NONE) && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
){ ){
i64 currentSize, newSize; i64 currentSize, newSize;
/* TODO: Is it safe to use Pager.dbFileSize here? */ /* TODO: Is it safe to use Pager.dbFileSize here? */
@@ -2785,7 +2846,7 @@ static int pagerBeginReadTransaction(Pager *pPager){
int changed = 0; /* True if cache must be reset */ int changed = 0; /* True if cache must be reset */
assert( pagerUseWal(pPager) ); assert( pagerUseWal(pPager) );
assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_READER ); assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
/* sqlite3WalEndReadTransaction() was not called for the previous /* sqlite3WalEndReadTransaction() was not called for the previous
** transaction in locking_mode=EXCLUSIVE. So call it now. If we ** transaction in locking_mode=EXCLUSIVE. So call it now. If we
@@ -2809,7 +2870,7 @@ static int pagerBeginReadTransaction(Pager *pPager){
static int pagerPagecount(Pager *pPager, Pgno *pnPage){ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
Pgno nPage; /* Value to return via *pnPage */ Pgno nPage; /* Value to return via *pnPage */
assert( pPager->eState==PAGER_NONE ); assert( pPager->eState==PAGER_OPEN );
nPage = sqlite3WalDbsize(pPager->pWal); nPage = sqlite3WalDbsize(pPager->pWal);
if( nPage==0 ){ if( nPage==0 ){
i64 n = 0; /* Size of db file in bytes */ i64 n = 0; /* Size of db file in bytes */
@@ -2865,7 +2926,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
int isWal; /* True if WAL file exists */ int isWal; /* True if WAL file exists */
Pgno nPage; /* Size of the database file */ Pgno nPage; /* Size of the database file */
assert( pPager->eState==PAGER_NONE ); assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );
rc = pagerPagecount(pPager, &nPage); rc = pagerPagecount(pPager, &nPage);
if( rc ) return rc; if( rc ) return rc;
@@ -2936,7 +2997,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */ Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */
assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState>=PAGER_WRITER_INITIAL ); assert( pPager->eState>=PAGER_WRITER_LOCKED );
/* Allocate a bitvec to use to store the set of pages rolled back */ /* Allocate a bitvec to use to store the set of pages rolled back */
if( pSavepoint ){ if( pSavepoint ){
@@ -3198,7 +3259,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){
){ ){
char *pNew; /* New temp space */ char *pNew; /* New temp space */
i64 nByte = 0; i64 nByte = 0;
if( pPager->eState>PAGER_NONE && isOpen(pPager->fd) ){ if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
rc = sqlite3OsFileSize(pPager->fd, &nByte); rc = sqlite3OsFileSize(pPager->fd, &nByte);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
} }
@@ -3246,7 +3307,7 @@ int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
if( mxPage>0 ){ if( mxPage>0 ){
pPager->mxPgno = mxPage; pPager->mxPgno = mxPage;
} }
if( pPager->eState!=PAGER_NONE && pPager->mxPgno<pPager->dbSize ){ if( pPager->eState!=PAGER_OPEN && pPager->mxPgno<pPager->dbSize ){
pPager->mxPgno = pPager->dbSize; pPager->mxPgno = pPager->dbSize;
} }
return pPager->mxPgno; return pPager->mxPgno;
@@ -3697,23 +3758,6 @@ static int syncJournal(Pager *pPager, int newHdr){
static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
int rc; /* Return code */ int rc; /* Return code */
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the
** database file. If there is already an EXCLUSIVE lock, the following
** call is a no-op.
**
** Moving the lock from RESERVED to EXCLUSIVE actually involves going
** through an intermediate state PENDING. A PENDING lock prevents new
** readers from attaching to the database but is unsufficient for us to
** write. The idea of a PENDING lock is to prevent new readers from
** coming in while we wait for existing readers to clear.
**
** While the pager is in the RESERVED state, the original database file
** is unchanged and we can rollback without having to playback the
** journal into the original database file. Once we transition to
** EXCLUSIVE, it means the database file has been changed and any rollback
** will require a journal playback.
*/
/* Normally, this function is called in WRITER_DBMOD state. /* Normally, this function is called in WRITER_DBMOD state.
** **
** However it may be called in WRITER_CACHEMOD state if the page being ** However it may be called in WRITER_CACHEMOD state if the page being
@@ -3730,6 +3774,22 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
|| (pList->pDirty==0 && pList->pgno<=pPager->dbFileSize) || (pList->pDirty==0 && pList->pgno<=pPager->dbFileSize)
); );
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the
** database file. If there is already an EXCLUSIVE lock, the following
** call is a no-op.
**
** Moving the lock from RESERVED to EXCLUSIVE actually involves going
** through an intermediate state PENDING. A PENDING lock prevents new
** readers from attaching to the database but is unsufficient for us to
** write. The idea of a PENDING lock is to prevent new readers from
** coming in while we wait for existing readers to clear.
**
** While the pager is in the RESERVED state, the original database file
** is unchanged and we can rollback without having to playback the
** journal into the original database file. Once we transition to
** EXCLUSIVE, it means the database file has been changed and any rollback
** will require a journal playback.
*/
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
/* If the file is a temp-file has not yet been opened, open it now. It /* If the file is a temp-file has not yet been opened, open it now. It
@@ -4318,7 +4378,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
assert( pPager->useJournal ); assert( pPager->useJournal );
assert( isOpen(pPager->fd) ); assert( isOpen(pPager->fd) );
assert( pPager->eState==PAGER_NONE ); assert( pPager->eState==PAGER_OPEN );
assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) & assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
@@ -4437,15 +4497,15 @@ int sqlite3PagerSharedLock(Pager *pPager){
/* This routine is only called from b-tree and only when there are no /* This routine is only called from b-tree and only when there are no
** outstanding pages. This implies that the pager state should either ** outstanding pages. This implies that the pager state should either
** be NONE or READER. READER is only possible if the pager is or was in ** be OPEN or READER. READER is only possible if the pager is or was in
** exclusive access mode. ** exclusive access mode.
*/ */
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_READER ); assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; } if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
if( !pagerUseWal(pPager) && pPager->eState==PAGER_NONE ){ if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
int bHotJournal = 1; /* True if there exists a hot journal-file */ int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB ); assert( !MEMDB );
@@ -4533,18 +4593,34 @@ int sqlite3PagerSharedLock(Pager *pPager){
rc = pagerSyncHotJournal(pPager); rc = pagerSyncHotJournal(pPager);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = pager_playback(pPager, 1); rc = pager_playback(pPager, 1);
pPager->eState = PAGER_NONE; pPager->eState = PAGER_OPEN;
} }
}else if( !pPager->exclusiveMode ){ }else if( !pPager->exclusiveMode ){
pagerUnlockDb(pPager, SHARED_LOCK); pagerUnlockDb(pPager, SHARED_LOCK);
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
/* This branch is taken if an error occurs while trying to open
** or roll back a hot-journal while holding an EXCLUSIVE lock. The
** pager_unlock() routine will be called before returning to unlock
** the file. If the unlock attempt fails, then Pager.eLock must be
** set to UNKNOWN_LOCK (see the comment above the #define for
** UNKNOWN_LOCK above for an explanation).
**
** In order to get pager_unlock() to do this, set Pager.eState to
** PAGER_ERROR now. This is not actually counted as a transition
** to ERROR state in the state diagram at the top of this file,
** since we know that the same call to pager_unlock() will very
** shortly transition the pager object to the OPEN state. Calling
** assert_pager_state() would fail now, as it should not be possible
** to be in ERROR state when there are zero outstanding page
** references.
*/
pager_error(pPager, rc); pager_error(pPager, rc);
goto failed; goto failed;
} }
assert( pPager->eState==PAGER_NONE ); assert( pPager->eState==PAGER_OPEN );
assert( (pPager->eLock==SHARED_LOCK) assert( (pPager->eLock==SHARED_LOCK)
|| (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
); );
@@ -4600,14 +4676,14 @@ int sqlite3PagerSharedLock(Pager *pPager){
rc = pagerBeginReadTransaction(pPager); rc = pagerBeginReadTransaction(pPager);
} }
if( pPager->eState==PAGER_NONE && rc==SQLITE_OK ){ if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
rc = pagerPagecount(pPager, &pPager->dbSize); rc = pagerPagecount(pPager, &pPager->dbSize);
} }
failed: failed:
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pager_unlock(pPager); pager_unlock(pPager);
assert( pPager->eState==PAGER_NONE ); assert( pPager->eState==PAGER_OPEN );
}else{ }else{
pPager->eState = PAGER_READER; pPager->eState = PAGER_READER;
} }
@@ -4847,7 +4923,7 @@ static int pager_open_journal(Pager *pPager){
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */ sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
assert( pPager->eState==PAGER_WRITER_INITIAL ); assert( pPager->eState==PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
@@ -4902,7 +4978,7 @@ static int pager_open_journal(Pager *pPager){
sqlite3BitvecDestroy(pPager->pInJournal); sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0; pPager->pInJournal = 0;
}else{ }else{
assert( pPager->eState==PAGER_WRITER_INITIAL ); assert( pPager->eState==PAGER_WRITER_LOCKED );
pPager->eState = PAGER_WRITER_CACHEMOD; pPager->eState = PAGER_WRITER_CACHEMOD;
} }
@@ -4974,29 +5050,22 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
/* Change to WRITER_INITIAL state. /* Change to WRITER_LOCKED state.
** **
** WAL mode sets Pager.eState to PAGER_WRITER_INITIAL or CACHEMOD ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD
** when it has an open transaction, but never to DBMOD or FINISHED. ** when it has an open transaction, but never to DBMOD or FINISHED.
** This is because in those states the code to roll back savepoint ** This is because in those states the code to roll back savepoint
** transactions may copy data from the sub-journal into the database ** transactions may copy data from the sub-journal into the database
** file as well as into the page cache. Which would be incorrect in ** file as well as into the page cache. Which would be incorrect in
** WAL mode. ** WAL mode.
*/ */
pPager->eState = PAGER_WRITER_INITIAL; pPager->eState = PAGER_WRITER_LOCKED;
pPager->dbFileSize = pPager->dbOrigSize = pPager->dbSize; pPager->dbFileSize = pPager->dbOrigSize = pPager->dbSize;
pPager->journalOff = 0; pPager->journalOff = 0;
}else{
/* Ignore any IO error that occurs within pager_end_transaction(). The
** purpose of this call is to reset the internal state of the pager
** sub-system. It doesn't matter if the journal-file is not properly
** finalized at this point (since it is not a valid journal file anyway).
*/
pager_end_transaction(pPager, 0);
} }
assert( rc==SQLITE_OK || pPager->eState==PAGER_READER ); assert( rc==SQLITE_OK || pPager->eState==PAGER_READER );
assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_INITIAL ); assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
} }
@@ -5020,7 +5089,7 @@ static int pager_write(PgHdr *pPg){
** been started. The journal file may or may not be open at this point. ** been started. The journal file may or may not be open at this point.
** It is never called in the ERROR state. ** It is never called in the ERROR state.
*/ */
assert( pPager->eState==PAGER_WRITER_INITIAL assert( pPager->eState==PAGER_WRITER_LOCKED
|| pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_CACHEMOD
|| pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_DBMOD
); );
@@ -5053,7 +5122,7 @@ static int pager_write(PgHdr *pPg){
** to begin the write-transaction, but the rollback journal might not ** to begin the write-transaction, but the rollback journal might not
** yet be open. Open it now if this is the case. ** yet be open. Open it now if this is the case.
*/ */
if( pPager->eState==PAGER_WRITER_INITIAL ){ if( pPager->eState==PAGER_WRITER_LOCKED ){
rc = pager_open_journal(pPager); rc = pager_open_journal(pPager);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
} }
@@ -5170,7 +5239,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
assert( pPager->eState>=PAGER_WRITER_INITIAL ); assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
@@ -5419,7 +5488,7 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
int rc = SQLITE_OK; int rc = SQLITE_OK;
assert( pPager->eState==PAGER_WRITER_CACHEMOD assert( pPager->eState==PAGER_WRITER_CACHEMOD
|| pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_DBMOD
|| pPager->eState==PAGER_WRITER_INITIAL || pPager->eState==PAGER_WRITER_LOCKED
); );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
if( 0==pagerUseWal(pPager) ){ if( 0==pagerUseWal(pPager) ){
@@ -5461,9 +5530,10 @@ int sqlite3PagerCommitPhaseOne(
){ ){
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
assert( pPager->eState==PAGER_WRITER_INITIAL assert( pPager->eState==PAGER_WRITER_LOCKED
|| pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_CACHEMOD
|| pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_DBMOD
|| pPager->eState==PAGER_WRITER_ERROR
); );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
@@ -5658,7 +5728,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
** called, just return the same error code without doing anything. */ ** called, just return the same error code without doing anything. */
if( NEVER(pPager->errCode) ) return pPager->errCode; if( NEVER(pPager->errCode) ) return pPager->errCode;
assert( pPager->eState==PAGER_WRITER_INITIAL assert( pPager->eState==PAGER_WRITER_LOCKED
|| pPager->eState==PAGER_WRITER_FINISHED || pPager->eState==PAGER_WRITER_FINISHED
|| (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD) || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD)
); );
@@ -5675,7 +5745,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
** header. Since the pager is in exclusive mode, there is no need ** header. Since the pager is in exclusive mode, there is no need
** to drop any locks either. ** to drop any locks either.
*/ */
if( pPager->eState==PAGER_WRITER_INITIAL if( pPager->eState==PAGER_WRITER_LOCKED
&& pPager->exclusiveMode && pPager->exclusiveMode
&& pPager->journalMode==PAGER_JOURNALMODE_PERSIST && pPager->journalMode==PAGER_JOURNALMODE_PERSIST
){ ){
@@ -5736,7 +5806,7 @@ int sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager))); PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
/* PagerRollback() is a no-op if called in READER or NONE state. If /* PagerRollback() is a no-op if called in READER or OPEN state. If
** the pager is already in the ERROR state, the rollback is not ** the pager is already in the ERROR state, the rollback is not
** attempted here. Instead, the error code is returned to the caller. ** attempted here. Instead, the error code is returned to the caller.
*/ */
@@ -5806,7 +5876,7 @@ int *sqlite3PagerStats(Pager *pPager){
a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[0] = sqlite3PcacheRefCount(pPager->pPCache);
a[1] = sqlite3PcachePagecount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache);
a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
a[3] = pPager->eState==PAGER_NONE ? -1 : (int) pPager->dbSize; a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
a[4] = pPager->eState; a[4] = pPager->eState;
a[5] = pPager->errCode; a[5] = pPager->errCode;
a[6] = pPager->nHit; a[6] = pPager->nHit;
@@ -5839,7 +5909,7 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
int nCurrent = pPager->nSavepoint; /* Current number of savepoints */ int nCurrent = pPager->nSavepoint; /* Current number of savepoints */
assert( pPager->eState>=PAGER_WRITER_INITIAL ); assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
if( nSavepoint>nCurrent && pPager->useJournal ){ if( nSavepoint>nCurrent && pPager->useJournal ){
@@ -6292,7 +6362,7 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
*/ */
int rc = SQLITE_OK; int rc = SQLITE_OK;
int state = pPager->eState; int state = pPager->eState;
if( state==PAGER_NONE ){ if( state==PAGER_OPEN ){
rc = sqlite3PagerSharedLock(pPager); rc = sqlite3PagerSharedLock(pPager);
} }
if( pPager->eState==PAGER_READER ){ if( pPager->eState==PAGER_READER ){
@@ -6304,7 +6374,7 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
} }
if( rc==SQLITE_OK && state==PAGER_READER ){ if( rc==SQLITE_OK && state==PAGER_READER ){
pagerUnlockDb(pPager, SHARED_LOCK); pagerUnlockDb(pPager, SHARED_LOCK);
}else if( state==PAGER_NONE ){ }else if( state==PAGER_OPEN ){
pager_unlock(pPager); pager_unlock(pPager);
} }
assert( state==pPager->eState ); assert( state==pPager->eState );
@@ -6408,7 +6478,7 @@ int sqlite3PagerOpenWal(
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
assert( pPager->eState==PAGER_NONE || pbOpen ); assert( pPager->eState==PAGER_OPEN || pbOpen );
assert( pPager->eState==PAGER_READER || !pbOpen ); assert( pPager->eState==PAGER_READER || !pbOpen );
assert( pbOpen==0 || *pbOpen==0 ); assert( pbOpen==0 || *pbOpen==0 );
assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) ); assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) );
@@ -6427,7 +6497,7 @@ int sqlite3PagerOpenWal(
rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal); rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pPager->journalMode = PAGER_JOURNALMODE_WAL; pPager->journalMode = PAGER_JOURNALMODE_WAL;
pPager->eState = PAGER_NONE; pPager->eState = PAGER_OPEN;
} }
}else{ }else{
*pbOpen = 1; *pbOpen = 1;