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

Add comments describing UNKNOWN_LOCK to pager.c. Improve some other comments i the same file.

FossilOrigin-Name: 54eff6de9d8d87f33192c192ca91907c4c090988
This commit is contained in:
dan
2010-08-05 18:53:26 +00:00
parent 4557b92cdb
commit 54919f8238
3 changed files with 98 additions and 84 deletions

View File

@@ -1,5 +1,5 @@
C Merge\strunk\schanges\swith\sexperimental\sbranch. C Add\scomments\sdescribing\sUNKNOWN_LOCK\sto\spager.c.\sImprove\ssome\sother\scomments\si\sthe\ssame\sfile.
D 2010-08-05T16:22:50 D 2010-08-05T18:53: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 7232578996c9ecd7b57bb9952a81549f2f133a4b F src/pager.c 07bda904e5b3e6fe6c9425a205fcaf1dca5a444c
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
@@ -842,7 +842,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 800f496929fb0d45d16c573c5dca0197ac922e2b ca479f3de2927ccc05dc76d10e40c00b8e0c88d1 P acd26b8b746980c344db017a0e96dbd92c89acdf
R 5a6390c995b69a7f924deee65f1b7dc5 R c079a70d95550574b0e39982e236e749
U dan U dan
Z 434bd8bfb5691e86b993c0ccfbfc4d4c Z 83b26f553c42e8e1edd2dad0b7de50dd

View File

@@ -1 +1 @@
acd26b8b746980c344db017a0e96dbd92c89acdf 54eff6de9d8d87f33192c192ca91907c4c090988

View File

@@ -163,12 +163,23 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** rollback (non-WAL) mode are met. Unless the pager is (or recently ** rollback (non-WAL) mode are met. Unless the pager is (or recently
** was) in exclusive-locking mode, a user-level read transaction is ** was) in exclusive-locking mode, a user-level read transaction is
** open. The database size is known in this state. ** open. The database size is known in this state.
**
** A connection running with locking_mode=normal enters this state when
** it opens a read-transaction on the database and returns to state
** NONE after the read-transaction is completed. However a connection
** running in locking_mode=exclusive (including temp databases) remains in
** this state even after the read-transaction is closed. The only way
** a locking_mode=exclusive connection can transition from READER to NONE
** is via the ERROR state (see below).
** **
** * A read transaction may be active. ** * 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
** transaction is not active). The dbOrigSize and dbFileSize variables ** transaction is not active). The dbOrigSize and dbFileSize variables
** may not be trusted at this point. ** may not be trusted at this point.
** * If the database is a WAL database, then the WAL connection is open.
** * Even if a read-transaction is not open, it is guaranteed that
** there is no hot-journal in the file-system.
** **
** WRITER_INITIAL: ** WRITER_INITIAL:
** **
@@ -290,62 +301,55 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
#define PAGER_WRITER_FINISHED 5 #define PAGER_WRITER_FINISHED 5
#define PAGER_ERROR 6 #define PAGER_ERROR 6
/* /*
** The page cache as a whole is always in one of the following ** The Pager.eLock variable is almost always set to one of the
** states: ** following locking-states, according to the lock currently held on
** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
** This variable is kept up to date as locks are taken and released by
** the pagerLockDb() and pagerUnlockDb() wrappers.
** **
** PAGER_UNLOCK The page cache is not currently reading or ** If the VFS xLock() or xUnlock() returns an error other than SQLITE_BUSY
** writing the database file. There is no ** (i.e. one of the SQLITE_IOERR subtypes), it is not clear whether or not
** data held in memory. This is the initial ** the operation was successful. In these circumstances pagerLockDb() and
** state. ** pagerUnlockDb() take a conservative approach - eLock is always updated
** when unlocking the file, and only updated when locking the file if the
** VFS call is successful. This way, the Pager.eLock variable may be set
** to a less exclusive (lower) value than the lock that is actually held
** at the system level, but it is never set to a more exclusive value.
** **
** PAGER_SHARED The page cache is reading the database. ** This is usually safe. If an xUnlock fails or appears to fail, there may
** Writing is not permitted. There can be ** be a few redundant xLock() calls or a lock may be held for longer than
** multiple readers accessing the same database ** required, but nothing really goes wrong.
** file at the same time.
** **
** PAGER_RESERVED This process has reserved the database for writing ** The exception is when the database file is unlocked as the pager moves
** but has not yet made any changes. Only one process ** from ERROR to NONE state. At this point there may be a hot-journal file
** at a time can reserve the database. The original ** in the file-system that needs to be rolled back (as part of a NONE->SHARED
** database file has not been modified so other ** transition, by the same pager or any other). If the call to xUnlock()
** processes may still be reading the on-disk ** fails at this point and the pager is left holding an EXCLUSIVE lock, this
** database file. ** can confuse the call to xCheckReservedLock() call made later as part
** of hot-journal detection.
** **
** PAGER_EXCLUSIVE The page cache is writing the database. ** xCheckReservedLock() is defined as returning true "if there is a RESERVED
** Access is exclusive. No other processes or ** lock held by this process or any others". So xCheckReservedLock may
** threads can be reading or writing while one ** return true because the caller itself is holding an EXCLUSIVE lock (but
** process is writing. ** doesn't know it because of a previous error in xUnlock). If this happens
** a hot-journal may be mistaken for a journal being created by an active
** transaction in another process, causing SQLite to read from the database
** without rolling it back.
** **
** PAGER_SYNCED The pager moves to this state from PAGER_EXCLUSIVE ** To work around this, if a call to xUnlock() fails when unlocking the
** after all dirty pages have been written to the ** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It
** database file and the file has been synced to ** is only changed back to a real locking state after a successful call
** disk. All that remains to do is to remove or ** to xLock(EXCLUSIVE). Also, the code to do the NONE->SHARED state transition
** truncate the journal file and the transaction ** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
** will be committed. ** 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
** PagerSharedLock() for more detail.
** **
** The page cache comes up in PAGER_UNLOCK. The first time a ** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
** sqlite3PagerGet() occurs, the state transitions to PAGER_SHARED. ** PAGER_NONE state.
** After all pages have been released using sqlite_page_unref(),
** the state transitions back to PAGER_UNLOCK. The first time
** that sqlite3PagerWrite() is called, the state transitions to
** PAGER_RESERVED. (Note that sqlite3PagerWrite() can only be
** called on an outstanding page which means that the pager must
** be in PAGER_SHARED before it transitions to PAGER_RESERVED.)
** PAGER_RESERVED means that there is an open rollback journal.
** The transition to PAGER_EXCLUSIVE occurs before any changes
** are made to the database file, though writes to the rollback
** journal occurs with just PAGER_RESERVED. After an sqlite3PagerRollback()
** or sqlite3PagerCommitPhaseTwo(), the state can go back to PAGER_SHARED,
** or it can stay at PAGER_EXCLUSIVE if we are in exclusive access mode.
*/ */
#define PAGER_UNLOCK 0 #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
#define PAGER_SHARED 1 /* same as SHARED_LOCK */
#define PAGER_RESERVED 2 /* same as RESERVED_LOCK */
#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
#define PAGER_SYNCED 5
#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
/* /*
** A macro used for invoking the codec if there is one ** A macro used for invoking the codec if there is one
@@ -398,14 +402,11 @@ struct PagerSavepoint {
** A open page cache is an instance of the following structure. ** A open page cache is an instance of the following structure.
** **
** errCode ** errCode
** 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_IOERR, SQLITE_CORRUPT, or ** Pager.errCode may be set to SQLITE_FULL, SQLITE_IOERR or one of the
** or SQLITE_FULL. Once one of the first three errors occurs, it persists ** SQLITE_IOERR_XXX sub-codes.
** and is returned as the result of every major pager API call. The
** SQLITE_FULL return code is slightly different. It persists only until the
** next successful rollback is performed on the pager cache. Also,
** SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup()
** APIs, they may still be used successfully.
** **
** dbSize, dbOrigSize, dbFileSize ** dbSize, dbOrigSize, dbFileSize
** **
@@ -418,10 +419,7 @@ struct PagerSavepoint {
** out from the cache to the actual file on disk. Or if the image has been ** out from the cache to the actual file on disk. Or if the image has been
** truncated by an incremental-vacuum operation. The Pager.dbOrigSize variable ** truncated by an incremental-vacuum operation. The Pager.dbOrigSize variable
** contains the number of pages in the database image when the current ** contains the number of pages in the database image when the current
** transaction was opened. The contents of all three of these variables is ** transaction was opened.
** only guaranteed to be correct if the boolean Pager.dbSizeValid is true.
**
** TODO: Under what conditions is dbSizeValid set? Cleared?
** **
** changeCountDone ** changeCountDone
** **
@@ -719,6 +717,7 @@ static int assert_pager_state(Pager *p){
** on the file. ** on the file.
*/ */
assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK ); assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
assert( p->eLock!=PENDING_LOCK );
switch( p->eState ){ switch( p->eState ){
case PAGER_NONE: case PAGER_NONE:
@@ -899,16 +898,22 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
} }
/* /*
** This function and pagerLockDb() are wrappers around sqlite3OsLock() and ** Unlock the database file to level eLock, which must be either NO_LOCK
** sqlite3OsUnlock() that set the Pager.eLock variable to reflect the ** or SHARED_LOCK. Regardless of whether or not the call to xUnlock()
** current lock held on the database file. ** succeeds, set the Pager.eLock variable to match the (attempted) new lock.
**
** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
** called, do not modify it. See the comment above the #define of
** UNKNOWN_LOCK for an explanation of this.
*/ */
static int pagerUnlockDb(Pager *pPager, int eLock){ static int pagerUnlockDb(Pager *pPager, int eLock){
int rc = SQLITE_OK; int rc = SQLITE_OK;
assert( !pPager->exclusiveMode ); assert( !pPager->exclusiveMode );
assert( eLock==NO_LOCK || eLock==SHARED_LOCK );
assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
if( isOpen(pPager->fd) ){ if( isOpen(pPager->fd) ){
assert( pPager->eLock>=eLock ); assert( pPager->eLock>=eLock );
assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
rc = sqlite3OsUnlock(pPager->fd, eLock); rc = sqlite3OsUnlock(pPager->fd, eLock);
if( pPager->eLock!=UNKNOWN_LOCK ){ if( pPager->eLock!=UNKNOWN_LOCK ){
pPager->eLock = eLock; pPager->eLock = eLock;
@@ -918,12 +923,21 @@ static int pagerUnlockDb(Pager *pPager, int eLock){
return rc; return rc;
} }
/*
** Lock the database file to level eLock, which must be either SHARED_LOCK,
** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
** Pager.eLock variable to the new locking state.
**
** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
** See the comment above the #define of UNKNOWN_LOCK for an explanation
** of this.
*/
static int pagerLockDb(Pager *pPager, int eLock){ static int pagerLockDb(Pager *pPager, int eLock){
int rc; int rc = SQLITE_OK;
assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK );
if( pPager->eLock>=eLock && pPager->eLock!=UNKNOWN_LOCK ){ if( pPager->eLock<eLock || pPager->eLock==UNKNOWN_LOCK ){
rc = SQLITE_OK;
}else{
rc = sqlite3OsLock(pPager->fd, eLock); rc = sqlite3OsLock(pPager->fd, eLock);
if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){
pPager->eLock = eLock; pPager->eLock = eLock;
@@ -1583,6 +1597,11 @@ static void pager_unlock(Pager *pPager){
sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->jfd);
} }
/* If the pager is in the ERROR state and the call to unlock the database
** file fails, set the current lock to UNKNOWN_LOCK. See the comment
** above the #define for UNKNOWN_LOCK for an explanation of why this
** is necessary.
*/
rc = pagerUnlockDb(pPager, NO_LOCK); rc = pagerUnlockDb(pPager, NO_LOCK);
if( rc!=SQLITE_OK && pPager->eState==PAGER_ERROR ){ if( rc!=SQLITE_OK && pPager->eState==PAGER_ERROR ){
pPager->eLock = UNKNOWN_LOCK; pPager->eLock = UNKNOWN_LOCK;
@@ -2750,7 +2769,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_SHARED ); assert( pPager->eState==PAGER_NONE || 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
@@ -3284,7 +3303,7 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
** this is considered a 1 page file. ** this is considered a 1 page file.
*/ */
int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
assert( pPager->eState>=PAGER_SHARED ); assert( pPager->eState>=PAGER_READER );
assert( pPager->eState!=PAGER_WRITER_FINISHED ); assert( pPager->eState!=PAGER_WRITER_FINISHED );
*pnPage = (int)pPager->dbSize; *pnPage = (int)pPager->dbSize;
return SQLITE_OK; return SQLITE_OK;
@@ -3308,11 +3327,6 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
static int pager_wait_on_lock(Pager *pPager, int locktype){ static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc; /* Return code */ int rc; /* Return code */
/* 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 );
/* Check that this is either a no-op (because the requested lock is /* Check that this is either a no-op (because the requested lock is
** already held, or one of the transistions that the busy-handler ** already held, or one of the transistions that the busy-handler
** may be invoked during, according to the comment above ** may be invoked during, according to the comment above
@@ -4424,7 +4438,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( pPager->noReadlock==0 ){ if( pPager->noReadlock==0 ){
rc = pager_wait_on_lock(pPager, SHARED_LOCK); rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
assert( pPager->eLock==PAGER_UNLOCK ); assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
goto failed; goto failed;
} }
} }
@@ -5393,7 +5407,7 @@ int sqlite3PagerExclusiveLock(Pager *pPager){
); );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
if( 0==pagerUseWal(pPager) ){ if( 0==pagerUseWal(pPager) ){
rc = pager_wait_on_lock(pPager, PAGER_EXCLUSIVE); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
} }
return rc; return rc;
} }