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

Incremental checkin on pager state refactoring.

FossilOrigin-Name: 0a636798bdb6961a47327091715b254f79add823
This commit is contained in:
dan
2010-08-03 06:42:39 +00:00
parent d08640871c
commit 763afe62e1
7 changed files with 144 additions and 94 deletions

View File

@@ -1,5 +1,5 @@
C Experimental\srefactoring\sof\sthe\sPager\sobject\sstate. C Incremental\scheckin\son\spager\sstate\srefactoring.
D 2010-08-02T14:32:52 D 2010-08-03T06:42:40
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 94f00bedf9afb83c47f9b5d8bf8608f0eff088dd F src/pager.c a22869257641c379545e482d843904702d027db7
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
@@ -207,7 +207,7 @@ F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8 F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
F src/test_stat.c 6ebaf2a86d01ccda24e49c148f1d33e8badda06e F src/test_stat.c dcabb7d39da058cbfc9ddc427cd92fbf14822b28
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0 F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
F src/test_vfs.c 7e291f85256516ebde6633bc381ff7eedfa30234 F src/test_vfs.c 7e291f85256516ebde6633bc381ff7eedfa30234
@@ -227,8 +227,8 @@ F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807 F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c 82200af3881fa4e1c9cf07cf31d98c09d437e3ab F src/vtab.c 82200af3881fa4e1c9cf07cf31d98c09d437e3ab
F src/wal.c 72cb5df7f4c26f83cb661d5a607b9918da99f758 F src/wal.c 6e04bccccd75acf86725cc8cb4b107cd245e018c
F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2 F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 79202ca81e740eeb1f54512147e29b6c518d84ca F src/where.c 79202ca81e740eeb1f54512147e29b6c518d84ca
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -547,7 +547,7 @@ F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16 F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
F test/permutations.test 3fe47c21c32b294b2354e702a25bfbff65747bb1 F test/permutations.test 17498d1219f922d5a6da893a94c4dc7766fb2426
F test/pragma.test ed78d200f65c6998df51196cb8c39d5300570f24 F test/pragma.test ed78d200f65c6998df51196cb8c39d5300570f24
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
@@ -841,7 +841,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 347f22a5b777af92873590a5b9af5a6498bef918 P 03a240514aa07a22db787d221641253f23933e88
R fb51b6835fc754e61c37a4fea5d6298b R 0befc920b01bc332d217d8425323f579
U dan U dan
Z 550ac78d14ba82c7a2ec704cc3fbe702 Z 0621f056ce54ddd71f6be378b7d6f549

View File

@@ -1 +1 @@
03a240514aa07a22db787d221641253f23933e88 0a636798bdb6961a47327091715b254f79add823

View File

@@ -130,13 +130,24 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** pager may be in any one of the following six states: ** pager may be in any one of the following six states:
** **
** NONE: ** NONE:
** 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
** unknown. The database may not be read or written.
**
** * No read or write transaction is active. ** * No read or write transaction is active.
** * Any lock, or no lock at all, may be held on the database file. ** * Any lock, or no lock at all, may be held on the database file.
** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted.
** **
** READER: ** READER:
** * A read transaction is active. ** 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
** open. The database size is known in this state.
**
** * A read transaction may be active.
** * 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 is valid. ** * The dbSize variable may be trusted (even if a user-level read
** transaction is not active).
** **
** WRITER_INITIAL: ** WRITER_INITIAL:
** * A write transaction is active. ** * A write transaction is active.
@@ -167,8 +178,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** commit the transaction. If an error did occur, the caller will need ** commit the transaction. If an error did occur, the caller will need
** to rollback the transaction. ** to rollback the transaction.
** **
** ** Allowable transitions and the [function] that performs each:
** Allowable transitions and the [function] that performe each:
** **
** NONE -> READER [PagerSharedLock] ** NONE -> READER [PagerSharedLock]
** READER -> WRITER_INITIAL [PagerBegin] ** READER -> WRITER_INITIAL [PagerBegin]
@@ -182,6 +192,19 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** WRITER_FINISHED -> READER [pager_end_transaction] ** WRITER_FINISHED -> READER [pager_end_transaction]
** **
** READER -> NONE [pager_unlock] ** READER -> NONE [pager_unlock]
**
** Notes:
**
** * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the
** connection is open in WAL mode. A WAL connection is always in one
** of the first four states.
**
** * Normally, a connection open in exclusive mode is never in PAGER_NONE
** state. There are two exceptions: immediately after exclusive-mode has
** been turned on (and before any read or write transactions are
** executed), and when the pager is leaving the "error state".
**
** * See also: assert_pager_state().
*/ */
#define PAGER_NONE 0 #define PAGER_NONE 0
#define PAGER_READER 1 #define PAGER_READER 1
@@ -425,8 +448,8 @@ struct Pager {
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
u8 dbModified; /* True if there are any changes to the Db */ u8 dbModified; /* True if there are any changes to the Db */
u8 journalStarted; /* True if header of journal is synced */ u8 journalStarted; /* True if header of journal is synced */
#endif
u8 dbSizeValid; /* Set when dbSize is correct */ u8 dbSizeValid; /* Set when dbSize is correct */
#endif
u8 eState; /* Pager state (NONE, READER, WRITER_INITIAL..) */ u8 eState; /* Pager state (NONE, READER, WRITER_INITIAL..) */
u8 eLock; /* Current lock held on database file */ u8 eLock; /* Current lock held on database file */
@@ -623,7 +646,6 @@ static int assert_pager_state(Pager *p){
case PAGER_NONE: case PAGER_NONE:
assert( !MEMDB ); assert( !MEMDB );
assert( !p->tempFile ); assert( !p->tempFile );
assert( !pagerUseWal(pPager) );
break; break;
case PAGER_READER: case PAGER_READER:
@@ -1348,7 +1370,6 @@ static void pager_reset(Pager *pPager){
if( SQLITE_OK==pPager->errCode ){ if( SQLITE_OK==pPager->errCode ){
sqlite3BackupRestart(pPager->pBackup); sqlite3BackupRestart(pPager->pBackup);
sqlite3PcacheClear(pPager->pPCache); sqlite3PcacheClear(pPager->pPCache);
pPager->dbSizeValid = 0;
} }
} }
@@ -1428,14 +1449,6 @@ static void pager_unlock(Pager *pPager){
pPager->pInJournal = 0; pPager->pInJournal = 0;
releaseAllSavepoints(pPager); releaseAllSavepoints(pPager);
/* If the file is unlocked, somebody else might change it. The
** values stored in Pager.dbSize etc. might become invalid if
** this happens. One can argue that this doesn't need to be cleared
** until the change-counter check fails in PagerSharedLock().
** Clearing the page size cache here is being conservative.
*/
pPager->dbSizeValid = 0;
if( pagerUseWal(pPager) ){ if( pagerUseWal(pPager) ){
sqlite3WalEndReadTransaction(pPager->pWal); sqlite3WalEndReadTransaction(pPager->pWal);
}else{ }else{
@@ -2589,6 +2602,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 );
/* 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
@@ -2598,19 +2612,41 @@ static int pagerBeginReadTransaction(Pager *pPager){
sqlite3WalEndReadTransaction(pPager->pWal); sqlite3WalEndReadTransaction(pPager->pWal);
rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK && changed ){
int dummy; pager_reset(pPager);
if( changed ){
pager_reset(pPager);
assert( pPager->errCode || pPager->dbSizeValid==0 );
}
rc = sqlite3PagerPagecount(pPager, &dummy);
} }
pPager->eState = PAGER_READER;
return rc; return rc;
} }
/*
** TODO: Description here.
*/
static int pagerPagecount(Pager *pPager, Pgno *pnPage){
Pgno nPage; /* Value to return via *pnPage */
assert( pPager->eState==PAGER_NONE );
nPage = sqlite3WalDbsize(pPager->pWal);
if( nPage==0 ){
i64 n = 0; /* Size of db file in bytes */
assert( isOpen(pPager->fd) || pPager->tempFile );
if( isOpen(pPager->fd) ){
int rc = sqlite3OsFileSize(pPager->fd, &n);
if( rc!=SQLITE_OK ){
return rc;
}
}
nPage = (Pgno)(n / pPager->pageSize);
if( nPage==0 && n>0 ){
nPage = 1;
}
}
*pnPage = nPage;
return SQLITE_OK;
}
/* /*
** Check if the *-wal file that corresponds to the database opened by pPager ** Check if the *-wal file that corresponds to the database opened by pPager
** exists if the database is not empy, or verify that the *-wal file does ** exists if the database is not empy, or verify that the *-wal file does
@@ -2635,10 +2671,11 @@ static int pagerOpenWalIfPresent(Pager *pPager){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( !pPager->tempFile ){ if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */ int isWal; /* True if WAL file exists */
int nPage; /* Size of the database file */ Pgno nPage; /* Size of the database file */
assert( pPager->eState==PAGER_NONE );
assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );
rc = sqlite3PagerPagecount(pPager, &nPage); rc = pagerPagecount(pPager, &nPage);
if( rc ) return rc; if( rc ) return rc;
if( nPage==0 ){ if( nPage==0 ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
@@ -2650,7 +2687,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
if( isWal ){ if( isWal ){
pager_reset(pPager); assert( sqlite3PcachePagecount(pPager->pPCache)==0 );
rc = sqlite3PagerOpenWal(pPager, 0); rc = sqlite3PagerOpenWal(pPager, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = pagerBeginReadTransaction(pPager); rc = pagerBeginReadTransaction(pPager);
@@ -2960,11 +2997,19 @@ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){
&& sqlite3PcacheRefCount(pPager->pPCache)==0 && sqlite3PcacheRefCount(pPager->pPCache)==0
&& pageSize && pageSize!=pPager->pageSize && pageSize && pageSize!=pPager->pageSize
){ ){
char *pNew = (char *)sqlite3PageMalloc(pageSize); char *pNew; /* New temp space */
i64 nByte = 0;
if( pPager->eState>PAGER_NONE && isOpen(pPager->fd) ){
rc = sqlite3OsFileSize(pPager->fd, &nByte);
if( rc!=SQLITE_OK ) return rc;
}
pNew = (char *)sqlite3PageMalloc(pageSize);
if( !pNew ){ if( !pNew ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{ }else{
assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_READER );
pager_reset(pPager); pager_reset(pPager);
pPager->dbSize = nByte/pageSize;
pPager->pageSize = pageSize; pPager->pageSize = pageSize;
sqlite3PageFree(pPager->pTmpSpace); sqlite3PageFree(pPager->pTmpSpace);
pPager->pTmpSpace = pNew; pPager->pTmpSpace = pNew;
@@ -3088,15 +3133,18 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
Pgno nPage = 0; /* Value to return via *pnPage */ Pgno nPage = 0; /* Value to return via *pnPage */
assert( pPager->eState>=PAGER_SHARED );
assert( pPager->eState!=PAGER_WRITER_FINISHED );
/* Determine the number of pages in the file. Store this in nPage. */ /* Determine the number of pages in the file. Store this in nPage. */
if( pPager->dbSizeValid ){ if( pPager->eState>PAGER_NONE ){
nPage = pPager->dbSize; nPage = pPager->dbSize;
}else{ }else{
int rc; /* Error returned by OsFileSize() */ int rc; /* Error returned by OsFileSize() */
i64 n = 0; /* File size in bytes returned by OsFileSize() */ i64 n = 0; /* File size in bytes returned by OsFileSize() */
if( pagerUseWal(pPager) && pPager->eState!=PAGER_NONE ){ if( pagerUseWal(pPager) && pPager->eState!=PAGER_NONE ){
sqlite3WalDbsize(pPager->pWal, &nPage); nPage = sqlite3WalDbsize(pPager->pWal);
} }
if( nPage==0 ){ if( nPage==0 ){
@@ -3116,7 +3164,6 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
if( pPager->eState!=PAGER_NONE ){ if( pPager->eState!=PAGER_NONE ){
pPager->dbSize = nPage; pPager->dbSize = nPage;
pPager->dbFileSize = nPage; pPager->dbFileSize = nPage;
pPager->dbSizeValid = 1;
} }
} }
@@ -3235,7 +3282,6 @@ static void assertTruncateConstraint(Pager *pPager){
** truncation will be done when the current transaction is committed. ** truncation will be done when the current transaction is committed.
*/ */
void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
assert( pPager->dbSizeValid );
assert( pPager->dbSize>=nPage ); assert( pPager->dbSize>=nPage );
assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
pPager->dbSize = nPage; pPager->dbSize = nPage;
@@ -4064,7 +4110,6 @@ int sqlite3PagerOpen(
/* pPager->stmtOpen = 0; */ /* pPager->stmtOpen = 0; */
/* pPager->stmtInUse = 0; */ /* pPager->stmtInUse = 0; */
/* pPager->nRef = 0; */ /* pPager->nRef = 0; */
pPager->dbSizeValid = (u8)memDb;
/* pPager->stmtSize = 0; */ /* pPager->stmtSize = 0; */
/* pPager->stmtJSize = 0; */ /* pPager->stmtJSize = 0; */
/* pPager->nPage = 0; */ /* pPager->nPage = 0; */
@@ -4146,10 +4191,9 @@ static int hasHotJournal(Pager *pPager, int *pExists){
int exists = 1; /* True if a journal file is present */ int exists = 1; /* True if a journal file is present */
int jrnlOpen = !!isOpen(pPager->jfd); int jrnlOpen = !!isOpen(pPager->jfd);
assert( pPager!=0 );
assert( pPager->useJournal ); assert( pPager->useJournal );
assert( isOpen(pPager->fd) ); assert( isOpen(pPager->fd) );
assert( pPager->eState<=PAGER_SHARED ); assert( pPager->eState==PAGER_NONE );
assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) & assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
@@ -4172,7 +4216,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
*/ */
rc = sqlite3OsCheckReservedLock(pPager->fd, &locked); rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
if( rc==SQLITE_OK && !locked ){ if( rc==SQLITE_OK && !locked ){
int nPage; Pgno nPage; /* Number of pages in database file */
/* Check the size of the database file. If it consists of 0 pages, /* Check the size of the database file. If it consists of 0 pages,
** then delete the journal file. See the header comment above for ** then delete the journal file. See the header comment above for
@@ -4180,7 +4224,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
** a RESERVED lock to avoid race conditions and to avoid violating ** a RESERVED lock to avoid race conditions and to avoid violating
** [H33020]. ** [H33020].
*/ */
rc = sqlite3PagerPagecount(pPager, &nPage); rc = pagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
if( nPage==0 ){ if( nPage==0 ){
sqlite3BeginBenignMalloc(); sqlite3BeginBenignMalloc();
@@ -4268,8 +4312,13 @@ int sqlite3PagerSharedLock(Pager *pPager){
int isErrorReset = 0; /* True if recovering from error state */ int isErrorReset = 0; /* True if recovering from error state */
/* 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 */ ** 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
** exclusive access mode.
*/
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_READER );
assert( assert_pager_state(pPager) );
if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; } if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
/* If this database is in an error-state, now is a chance to clear /* If this database is in an error-state, now is a chance to clear
@@ -4281,14 +4330,12 @@ int sqlite3PagerSharedLock(Pager *pPager){
isErrorReset = 1; isErrorReset = 1;
} }
pPager->errCode = SQLITE_OK; pPager->errCode = SQLITE_OK;
pPager->eState = PAGER_NONE;
pager_reset(pPager); pager_reset(pPager);
} }
if( pagerUseWal(pPager) ){ if( !pagerUseWal(pPager) && pPager->eState==PAGER_NONE ){
rc = pagerBeginReadTransaction(pPager);
}else if( pPager->eState==PAGER_NONE || isErrorReset ){
sqlite3_vfs * const pVfs = pPager->pVfs; sqlite3_vfs * const pVfs = pPager->pVfs;
int isHotJournal = 0;
assert( !MEMDB && !pPager->tempFile ); assert( !MEMDB && !pPager->tempFile );
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
@@ -4301,18 +4348,17 @@ int sqlite3PagerSharedLock(Pager *pPager){
return pager_error(pPager, rc); return pager_error(pPager, rc);
} }
} }
pPager->eState = PAGER_READER;
/* If a journal file exists, and there is no RESERVED lock on the /* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted. ** database file, then it either needs to be played back or deleted.
*/ */
if( !isErrorReset ){ if( !isErrorReset ){
rc = hasHotJournal(pPager, &isHotJournal); rc = hasHotJournal(pPager, &isErrorReset);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto failed; goto failed;
} }
} }
if( isErrorReset || isHotJournal ){ if( isErrorReset ){
/* Get an EXCLUSIVE lock on the database file. At this point it is /* Get an EXCLUSIVE lock on the database file. At this point it is
** important that a RESERVED lock is not obtained on the way to the ** important that a RESERVED lock is not obtained on the way to the
** EXCLUSIVE lock. If it were, another process might open the ** EXCLUSIVE lock. If it were, another process might open the
@@ -4389,7 +4435,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pPager->eState = PAGER_WRITER_FINISHED; pPager->eState = PAGER_WRITER_FINISHED;
rc = pager_playback(pPager, 1); rc = pager_playback(pPager, 1);
pPager->eState = PAGER_READER; pPager->eState = PAGER_NONE;
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
rc = pager_error(pPager, rc); rc = pager_error(pPager, rc);
@@ -4399,7 +4445,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
osUnlock(pPager, SHARED_LOCK); osUnlock(pPager, SHARED_LOCK);
} }
assert( pPager->eState==PAGER_READER ); assert( pPager->eState==PAGER_NONE );
assert( (pPager->eLock==SHARED_LOCK) assert( (pPager->eLock==SHARED_LOCK)
|| (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK)
); );
@@ -4422,14 +4468,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
** detected. The chance of an undetected change is so small that ** detected. The chance of an undetected change is so small that
** it can be neglected. ** it can be neglected.
*/ */
int nPage = 0; Pgno nPage = 0;
char dbFileVers[sizeof(pPager->dbFileVers)]; char dbFileVers[sizeof(pPager->dbFileVers)];
sqlite3PagerPagecount(pPager, &nPage);
if( pPager->errCode ){ rc = pagerPagecount(pPager, &nPage);
rc = pPager->errCode; if( rc ) goto failed;
goto failed;
}
if( nPage>0 ){ if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
@@ -4445,7 +4488,6 @@ int sqlite3PagerSharedLock(Pager *pPager){
pager_reset(pPager); pager_reset(pPager);
} }
} }
assert( pPager->eState==PAGER_READER );
/* If there is a WAL file in the file-system, open this database in WAL /* If there is a WAL file in the file-system, open this database in WAL
** mode. Otherwise, the following function call is a no-op. ** mode. Otherwise, the following function call is a no-op.
@@ -4453,10 +4495,21 @@ int sqlite3PagerSharedLock(Pager *pPager){
rc = pagerOpenWalIfPresent(pPager); rc = pagerOpenWalIfPresent(pPager);
} }
if( pagerUseWal(pPager) && rc==SQLITE_OK ){
rc = pagerBeginReadTransaction(pPager);
}
if( pPager->eState==PAGER_NONE && rc==SQLITE_OK ){
pPager->eState = PAGER_NONE;
rc = pagerPagecount(pPager, &pPager->dbSize);
}
failed: failed:
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
/* pager_unlock() is a no-op for exclusive mode and in-memory databases. */ /* pager_unlock() is a no-op for exclusive mode and in-memory databases. */
pager_unlock(pPager); pager_unlock(pPager);
}else{
pPager->eState = PAGER_READER;
} }
return rc; return rc;
} }
@@ -4713,7 +4766,6 @@ static int pager_open_journal(Pager *pPager){
if( NEVER(pPager->errCode) ) return pPager->errCode; if( NEVER(pPager->errCode) ) return pPager->errCode;
if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
testcase( pPager->dbSizeValid==0 );
rc = sqlite3PagerPagecount(pPager, &nPage); rc = sqlite3PagerPagecount(pPager, &nPage);
if( rc ) return rc; if( rc ) return rc;
pPager->pInJournal = sqlite3BitvecCreate(nPage); pPager->pInJournal = sqlite3BitvecCreate(nPage);
@@ -5636,10 +5688,6 @@ int sqlite3PagerRollback(Pager *pPager){
rc = pager_playback(pPager, 0); rc = pager_playback(pPager, 0);
} }
if( !MEMDB ){
pPager->dbSizeValid = 0;
}
/* If an error occurs during a ROLLBACK, we can no longer trust the pager /* 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 ** cache. So call pager_error() on the way out to make any error
** persistent. ** persistent.
@@ -5692,7 +5740,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->dbSizeValid ? (int) pPager->dbSize : -1; a[3] = pPager->eState==PAGER_NONE ? -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;
@@ -6010,7 +6058,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
if( MEMDB ){ if( MEMDB ){
/* Do not discard pages from an in-memory database since we might /* Do not discard pages from an in-memory database since we might
** need to rollback later. Just move the page out of the way. */ ** need to rollback later. Just move the page out of the way. */
assert( pPager->dbSizeValid );
sqlite3PcacheMove(pPgOld, pPager->dbSize+1); sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
}else{ }else{
sqlite3PcacheDrop(pPgOld); sqlite3PcacheDrop(pPgOld);
@@ -6287,21 +6334,24 @@ int sqlite3PagerWalSupported(Pager *pPager){
** file (not a temp file or an in-memory database), and the WAL file ** file (not a temp file or an in-memory database), and the WAL file
** is not already open, make an attempt to open it now. If successful, ** is not already open, make an attempt to open it now. If successful,
** return SQLITE_OK. If an error occurs or the VFS used by the pager does ** return SQLITE_OK. If an error occurs or the VFS used by the pager does
** not support the xShmXXX() methods, return an error code. *pisOpen is ** not support the xShmXXX() methods, return an error code. *pbOpen is
** not modified in either case. ** not modified in either case.
** **
** If the pager is open on a temp-file (or in-memory database), or if ** If the pager is open on a temp-file (or in-memory database), or if
** the WAL file is already open, set *pisOpen to 1 and return SQLITE_OK ** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
** without doing anything. ** without doing anything.
*/ */
int sqlite3PagerOpenWal( int sqlite3PagerOpenWal(
Pager *pPager, /* Pager object */ Pager *pPager, /* Pager object */
int *pisOpen /* OUT: Set to true if call is a no-op */ int *pbOpen /* OUT: Set to true if call is a no-op */
){ ){
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) );
assert( (pisOpen==0 && !pPager->tempFile && !pPager->pWal) || *pisOpen==0 ); assert( pPager->eState==PAGER_NONE || pbOpen );
assert( pPager->eState==PAGER_READER || !pbOpen );
assert( pbOpen==0 || *pbOpen==0 );
assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) );
if( !pPager->tempFile && !pPager->pWal ){ if( !pPager->tempFile && !pPager->pWal ){
if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN; if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
@@ -6313,9 +6363,10 @@ 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;
} }
}else{ }else{
*pisOpen = 1; *pbOpen = 1;
} }
return rc; return rc;

View File

@@ -376,7 +376,13 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
if( pCsr->aPage[0].pPg==0 ){ if( pCsr->aPage[0].pPg==0 ){
rc = sqlite3_step(pCsr->pStmt); rc = sqlite3_step(pCsr->pStmt);
if( rc==SQLITE_ROW ){ if( rc==SQLITE_ROW ){
int nPage;
u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1); u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1);
sqlite3PagerPagecount(pPager, &nPage);
if( nPage==0 ){
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
}
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iPgno = iRoot;
pCsr->aPage[0].iCell = 0; pCsr->aPage[0].iCell = 0;
@@ -486,17 +492,9 @@ static int statFilter(
int idxNum, const char *idxStr, int idxNum, const char *idxStr,
int argc, sqlite3_value **argv int argc, sqlite3_value **argv
){ ){
sqlite3 *db = ((StatTable *)(pCursor->pVtab))->db;
StatCursor *pCsr = (StatCursor *)pCursor; StatCursor *pCsr = (StatCursor *)pCursor;
int nPage = 0;
statResetCsr((StatCursor *)pCursor); statResetCsr((StatCursor *)pCursor);
sqlite3PagerPagecount(sqlite3BtreePager(db->aDb[0].pBt), &nPage);
if( nPage==0 ){
pCsr->isEof = 1;
return SQLITE_OK;
}
return statNext(pCursor); return statNext(pCursor);
} }

View File

@@ -2166,11 +2166,13 @@ int sqlite3WalRead(
/* /*
** Set *pPgno to the size of the database file (or zero, if unknown). ** Return the size of the database in pages (or zero, if unknown).
*/ */
void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno){ Pgno sqlite3WalDbsize(Wal *pWal){
assert( pWal->readLock>=0 || pWal->lockError ); if( pWal && pWal->readLock>=0 ){
*pPgno = pWal->hdr.nPage; return pWal->hdr.nPage;
}
return 0;
} }

View File

@@ -25,7 +25,7 @@
# define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0
# define sqlite3WalEndReadTransaction(z) # define sqlite3WalEndReadTransaction(z)
# define sqlite3WalRead(v,w,x,y,z) 0 # define sqlite3WalRead(v,w,x,y,z) 0
# define sqlite3WalDbsize(y,z) # define sqlite3WalDbsize(y) 0
# define sqlite3WalBeginWriteTransaction(y) 0 # define sqlite3WalBeginWriteTransaction(y) 0
# define sqlite3WalEndWriteTransaction(x) 0 # define sqlite3WalEndWriteTransaction(x) 0
# define sqlite3WalUndo(x,y,z) 0 # define sqlite3WalUndo(x,y,z) 0
@@ -61,9 +61,8 @@ void sqlite3WalEndReadTransaction(Wal *pWal);
/* Read a page from the write-ahead log, if it is present. */ /* Read a page from the write-ahead log, if it is present. */
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut); int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
/* Return the size of the database as it existed at the beginning /* If the WAL is not empty, return the size of the database. */
** of the snapshot */ Pgno sqlite3WalDbsize(Wal *pWal);
void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
/* Obtain or release the WRITER lock. */ /* Obtain or release the WRITER lock. */
int sqlite3WalBeginWriteTransaction(Wal *pWal); int sqlite3WalBeginWriteTransaction(Wal *pWal);

View File

@@ -129,7 +129,7 @@ test_suite "veryquick" -prefix "" -description {
This test suite is the same as the "quick" tests, except that some files This test suite is the same as the "quick" tests, except that some files
that test malloc and IO errors are omitted. that test malloc and IO errors are omitted.
} -files [ } -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* test_set $allquicktests -exclude *malloc* *ioerr* *fault*
] ]
test_suite "quick" -prefix "" -description { test_suite "quick" -prefix "" -description {