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

Allow read-only cursors to use mmap pages even if there is an open write transaction.

FossilOrigin-Name: b387e2f9d24dccac1fd040e309f6fc7ec1cfffba
This commit is contained in:
dan
2013-03-15 18:29:18 +00:00
parent b2d3de3bf4
commit 11dcd11913
5 changed files with 124 additions and 76 deletions

View File

@@ -1,5 +1,5 @@
C Use\smmap()\sto\sread\sfrom\sthe\sdatabase\sfile\sin\srollback\smode.\sThis\sbranch\sis\sunix\sonly\sfor\snow. C Allow\sread-only\scursors\sto\suse\smmap\spages\seven\sif\sthere\sis\san\sopen\swrite\stransaction.
D 2013-03-14T18:34:37.796 D 2013-03-15T18:29:18.146
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 9a804abbd3cae82d196e4d33aba13239e32522a5 F Makefile.in 9a804abbd3cae82d196e4d33aba13239e32522a5
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -121,7 +121,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c b2cac9f7993f3f9588827b824b1501d0c820fa68 F src/backup.c b2cac9f7993f3f9588827b824b1501d0c820fa68
F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1 F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c c1a956c6762f2a45188c945e1070daec29f5253f F src/btree.c 934921ec91456c264f61ce671ca62cb826af977a
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
F src/build.c 375e5df716e03b9343c5e1211be3b24e6d6dff05 F src/build.c 375e5df716e03b9343c5e1211be3b24e6d6dff05
@@ -162,8 +162,8 @@ F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 2a4cd96aabf413f39cf562baebb27aa9993f6f54 F src/os_unix.c 2a4cd96aabf413f39cf562baebb27aa9993f6f54
F src/os_win.c f7da4dc0a2545c0a430080380809946ae4d676d6 F src/os_win.c f7da4dc0a2545c0a430080380809946ae4d676d6
F src/pager.c 4e7e66c2959ee43caf8a7000712d6a4121b0888a F src/pager.c 734578514314a3d923fa1399c9722acbcc4f7e6b
F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0 F src/pager.h 81ac95f4fcfe21981f495146f6d7f2fe51afd110
F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95 F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
@@ -1038,10 +1038,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P 0b452734faa0839c817f040322e7733e423bfce2 P 6f21d9cbf5d457e63a7282015a89ae785526cf6d
R d4c281f6a900c9b41816881ffb3c2331 R 94aae53403ccd6ebc7d159fa0d23eb33
T *branch * experimental-mmap
T *sym-experimental-mmap *
T -sym-trunk *
U dan U dan
Z f16a594407ec9e95c26319dfbc751443 Z 133f9be54c97c4ee392fb0706f346b90

View File

@@ -1 +1 @@
6f21d9cbf5d457e63a7282015a89ae785526cf6d b387e2f9d24dccac1fd040e309f6fc7ec1cfffba

View File

@@ -1569,13 +1569,17 @@ static int btreeGetPage(
BtShared *pBt, /* The btree */ BtShared *pBt, /* The btree */
Pgno pgno, /* Number of the page to fetch */ Pgno pgno, /* Number of the page to fetch */
MemPage **ppPage, /* Return the page in this parameter */ MemPage **ppPage, /* Return the page in this parameter */
int noContent /* Do not load page content if true */ int noContent, /* Do not load page content if true */
int bReadonly /* True if a read-only (mmap) page is ok */
){ ){
int rc; int rc;
DbPage *pDbPage; DbPage *pDbPage;
int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0)
| (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
assert( noContent==0 || bReadonly==0 );
assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3_mutex_held(pBt->mutex) );
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent); rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
if( rc ) return rc; if( rc ) return rc;
*ppPage = btreePageFromDbPage(pDbPage, pgno, pBt); *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
return SQLITE_OK; return SQLITE_OK;
@@ -1618,9 +1622,10 @@ u32 sqlite3BtreeLastPage(Btree *p){
** may remain unchanged, or it may be set to an invalid value. ** may remain unchanged, or it may be set to an invalid value.
*/ */
static int getAndInitPage( static int getAndInitPage(
BtShared *pBt, /* The database file */ BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */ Pgno pgno, /* Number of the page to get */
MemPage **ppPage /* Write the page pointer here */ MemPage **ppPage, /* Write the page pointer here */
int bReadonly /* True if a read-only (mmap) page is ok */
){ ){
int rc; int rc;
assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3_mutex_held(pBt->mutex) );
@@ -1628,7 +1633,7 @@ static int getAndInitPage(
if( pgno>btreePagecount(pBt) ){ if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
}else{ }else{
rc = btreeGetPage(pBt, pgno, ppPage, 0); rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = btreeInitPage(*ppPage); rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -2350,7 +2355,7 @@ static int lockBtree(BtShared *pBt){
assert( pBt->pPage1==0 ); assert( pBt->pPage1==0 );
rc = sqlite3PagerSharedLock(pBt->pPager); rc = sqlite3PagerSharedLock(pBt->pPager);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
rc = btreeGetPage(pBt, 1, &pPage1, 0); rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is /* Do some checking to help insure the file we opened really is
@@ -2565,31 +2570,30 @@ int sqlite3BtreeNewDb(Btree *p){
} }
/* /*
** If the shared-btree passed as the only argument is holding references ** Ensure that any root page references held by open cursors are not
** to mmap pages, replace them with read/write pages. Return SQLITE_OK ** mmap pages.
** if successful, or an error code otherwise.
*/ */
static int btreeSwapOutMmap(BtShared *pBt){ static int btreeSwapOutMmap(BtShared *pBt){
BtCursor *pCsr; int rc = SQLITE_OK; /* Return code */
for(pCsr=pBt->pCursor; pCsr; pCsr=pCsr->pNext){ BtCursor *pCsr; /* Used to iterate through all open cursors */
int i;
for(i=0; i<=pCsr->iPage; i++){ for(pCsr=pBt->pCursor; pCsr && rc==SQLITE_OK; pCsr=pCsr->pNext){
MemPage *pPg = pCsr->apPage[i]; if( pCsr->iPage>=0 ){
MemPage *pPg = pCsr->apPage[0];
if( pPg->pDbPage->flags & PGHDR_MMAP ){ if( pPg->pDbPage->flags & PGHDR_MMAP ){
int rc;
MemPage *pNew = 0; MemPage *pNew = 0;
rc = btreeGetPage(pBt, pPg->pgno, &pNew, 0); rc = btreeGetPage(pBt, pPg->pgno, &pNew, 0, 0);
if( rc==SQLITE_OK && i==pCsr->iPage ){ if( rc==SQLITE_OK && pCsr->iPage==0 ){
pCsr->info.pCell = pNew->aData + (pCsr->info.pCell - pPg->aData); pCsr->info.pCell = pNew->aData + (pCsr->info.pCell - pPg->aData);
} }
pCsr->apPage[i] = pNew; pCsr->apPage[0] = pNew;
releasePage(pPg); releasePage(pPg);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
} }
} }
} }
return SQLITE_OK; return rc;
} }
/* /*
@@ -2940,7 +2944,7 @@ static int relocatePage(
** iPtrPage. ** iPtrPage.
*/ */
if( eType!=PTRMAP_ROOTPAGE ){ if( eType!=PTRMAP_ROOTPAGE ){
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0); rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -3024,7 +3028,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -3116,8 +3120,11 @@ int sqlite3BtreeIncrVacuum(Btree *p){
if( nOrig<nFin ){ if( nOrig<nFin ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
}else if( nFree>0 ){ }else if( nFree>0 ){
invalidateAllOverflowCache(pBt); rc = saveAllCursors(pBt, 0, 0);
rc = incrVacuumStep(pBt, nFin, nOrig, 0); if( rc==SQLITE_OK ){
invalidateAllOverflowCache(pBt);
rc = incrVacuumStep(pBt, nFin, nOrig, 0);
}
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[28], pBt->nPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage);
@@ -3438,7 +3445,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
/* The rollback may have destroyed the pPage1->aData value. So /* The rollback may have destroyed the pPage1->aData value. So
** call btreeGetPage() on page 1 again to make ** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */ ** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
int nPage = get4byte(28+(u8*)pPage1->aData); int nPage = get4byte(28+(u8*)pPage1->aData);
testcase( nPage==0 ); testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
@@ -3872,7 +3879,7 @@ static int getOverflowPage(
assert( next==0 || rc==SQLITE_DONE ); assert( next==0 || rc==SQLITE_DONE );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = btreeGetPage(pBt, ovfl, &pPage, 0); rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
assert( rc==SQLITE_OK || pPage==0 ); assert( rc==SQLITE_OK || pPage==0 );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
next = get4byte(pPage->aData); next = get4byte(pPage->aData);
@@ -4093,7 +4100,9 @@ static int accessPayload(
{ {
DbPage *pDbPage; DbPage *pDbPage;
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage); rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
(eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage); aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload); nextPage = get4byte(aPayload);
@@ -4272,10 +4281,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( cursorHoldsMutex(pCur) ); assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getAndInitPage(pBt, newPgno, &pNewPage); rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
if( rc ) return rc; if( rc ) return rc;
pCur->apPage[i+1] = pNewPage; pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0; pCur->aiIdx[i+1] = 0;
@@ -4392,7 +4402,7 @@ static int moveToRoot(BtCursor *pCur){
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
return SQLITE_OK; return SQLITE_OK;
}else{ }else{
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
return rc; return rc;
@@ -5006,7 +5016,7 @@ static int allocateBtreePage(
if( iTrunk>mxPage ){ if( iTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
}else{ }else{
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
} }
if( rc ){ if( rc ){
pTrunk = 0; pTrunk = 0;
@@ -5070,7 +5080,7 @@ static int allocateBtreePage(
goto end_allocate_page; goto end_allocate_page;
} }
testcase( iNewTrunk==mxPage ); testcase( iNewTrunk==mxPage );
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0); rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto end_allocate_page; goto end_allocate_page;
} }
@@ -5150,7 +5160,7 @@ static int allocateBtreePage(
} }
put4byte(&aData[4], k-1); put4byte(&aData[4], k-1);
noContent = !btreeGetHasContent(pBt, *pPgno); noContent = !btreeGetHasContent(pBt, *pPgno);
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent); rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -5198,7 +5208,7 @@ static int allocateBtreePage(
MemPage *pPg = 0; MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent); rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage); rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg); releasePage(pPg);
@@ -5212,7 +5222,7 @@ static int allocateBtreePage(
*pPgno = pBt->nPage; *pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent); rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
if( rc ) return rc; if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -5280,7 +5290,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the secure_delete option is enabled, then /* If the secure_delete option is enabled, then
** always fully overwrite deleted information with zeros. ** always fully overwrite deleted information with zeros.
*/ */
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) ) if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0) || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
){ ){
goto freepage_out; goto freepage_out;
@@ -5307,7 +5317,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */ u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]); iTrunk = get4byte(&pPage1->aData[32]);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto freepage_out; goto freepage_out;
} }
@@ -5353,7 +5363,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** first trunk in the free-list is full. Either way, the page being freed ** first trunk in the free-list is full. Either way, the page being freed
** will become the new first trunk page in the free-list. ** will become the new first trunk page in the free-list.
*/ */
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){ if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
goto freepage_out; goto freepage_out;
} }
rc = sqlite3PagerWrite(pPage->pDbPage); rc = sqlite3PagerWrite(pPage->pDbPage);
@@ -6154,7 +6164,7 @@ static int balance_nonroot(
} }
pgno = get4byte(pRight); pgno = get4byte(pRight);
while( 1 ){ while( 1 ){
rc = getAndInitPage(pBt, pgno, &apOld[i]); rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
if( rc ){ if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*)); memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup; goto balance_cleanup;
@@ -7245,7 +7255,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
releasePage(pPageMove); releasePage(pPageMove);
/* Move the page currently at pgnoRoot to pgnoMove. */ /* Move the page currently at pgnoRoot to pgnoMove. */
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -7266,7 +7276,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -7342,7 +7352,7 @@ static int clearDatabasePage(
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getAndInitPage(pBt, pgno, &pPage); rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc; if( rc ) return rc;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i); pCell = findCell(pPage, i);
@@ -7444,7 +7454,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return SQLITE_LOCKED_SHAREDCACHE; return SQLITE_LOCKED_SHAREDCACHE;
} }
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
if( rc ) return rc; if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable, 0); rc = sqlite3BtreeClearTable(p, iTable, 0);
if( rc ){ if( rc ){
@@ -7479,7 +7489,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
*/ */
MemPage *pMove; MemPage *pMove;
releasePage(pPage); releasePage(pPage);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -7489,7 +7499,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return rc; return rc;
} }
pMove = 0; pMove = 0;
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
freePage(pMove, &rc); freePage(pMove, &rc);
releasePage(pMove); releasePage(pMove);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -7901,7 +7911,7 @@ static int checkTreePage(
usableSize = pBt->usableSize; usableSize = pBt->usableSize;
if( iPage==0 ) return 0; if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
checkAppendMsg(pCheck, zContext, checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc); "unable to get the page. error code=%d", rc);
return 0; return 0;

View File

@@ -658,6 +658,7 @@ struct Pager {
void *pMap; /* Memory mapped prefix of database file */ void *pMap; /* Memory mapped prefix of database file */
i64 nMap; /* Size of mapping at pMap in bytes */ i64 nMap; /* Size of mapping at pMap in bytes */
i64 nMapValid; /* Bytes at pMap known to be valid */
int nMmapOut; /* Number of mmap pages currently outstanding */ int nMmapOut; /* Number of mmap pages currently outstanding */
PgHdr *pFree; /* List of free mmap page headers (pDirty) */ PgHdr *pFree; /* List of free mmap page headers (pDirty) */
/* /*
@@ -2512,6 +2513,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
if( rc==SQLITE_OK && currentSize!=newSize ){ if( rc==SQLITE_OK && currentSize!=newSize ){
if( currentSize>newSize ){ if( currentSize>newSize ){
rc = sqlite3OsTruncate(pPager->fd, newSize); rc = sqlite3OsTruncate(pPager->fd, newSize);
if( newSize<pPager->nMapValid ){
pPager->nMapValid = newSize;
}
}else if( (currentSize+szPage)<=newSize ){ }else if( (currentSize+szPage)<=newSize ){
char *pTmp = pPager->pTmpSpace; char *pTmp = pPager->pTmpSpace;
memset(pTmp, 0, szPage); memset(pTmp, 0, szPage);
@@ -3818,6 +3822,7 @@ static int pagerUnmap(Pager *pPager){
munmap(pPager->pMap, pPager->nMap); munmap(pPager->pMap, pPager->nMap);
pPager->pMap = 0; pPager->pMap = 0;
pPager->nMap = 0; pPager->nMap = 0;
pPager->nMapValid = 0;
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -3839,7 +3844,7 @@ static int pagerMap(Pager *pPager){
return SQLITE_IOERR; return SQLITE_IOERR;
} }
pPager->pMap = pMap; pPager->pMap = pMap;
pPager->nMap = sz; pPager->nMapValid = pPager->nMap = sz;
} }
} }
@@ -3858,7 +3863,9 @@ static int pagerAcquireMapPage(Pager *pPager, Pgno pgno, PgHdr **ppPage){
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
} }
if( pgno!=1 && pPager->pMap && pPager->nMap>=((i64)pgno*pPager->pageSize) ){ if( pgno!=1 && pPager->pMap
&& pPager->nMapValid>=((i64)pgno*pPager->pageSize)
){
PgHdr *p; PgHdr *p;
if( pPager->pFree ){ if( pPager->pFree ){
p = pPager->pFree; p = pPager->pFree;
@@ -5035,9 +5042,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
); );
} }
if( !pPager->tempFile if( !pPager->tempFile && (
&& (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0) pPager->pBackup
){ || sqlite3PcachePagecount(pPager->pPCache)>0
|| pPager->pMap
)){
/* The shared-lock has just been acquired on the database file /* The shared-lock has just been acquired on the database file
** and there are already pages in the cache (from a previous ** and there are already pages in the cache (from a previous
** read or write transaction). Check to see if the database ** read or write transaction). Check to see if the database
@@ -5072,6 +5081,15 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
pager_reset(pPager); pager_reset(pPager);
/* Unmap the database file. It is possible that external processes
** may have truncated the database file and then extended it back
** to its original size while this process was not holding a lock.
** In this case there may exist a Pager.pMap mapping that appears
** to be the right size but is not actually valid. Avoid this
** possibility by unmapping the db here. */
pagerUnmap(pPager);
}else if( ((i64)nPage*pPager->pageSize)!=pPager->nMap ){
pagerUnmap(pPager); pagerUnmap(pPager);
} }
} }
@@ -5173,10 +5191,20 @@ int sqlite3PagerAcquire(
Pager *pPager, /* The pager open on the database file */ Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */ Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */ DbPage **ppPage, /* Write a pointer to the page here */
int noContent /* Do not bother reading content from disk if true */ int flags /* PAGER_ACQUIRE_XXX flags */
){ ){
int rc; int rc = SQLITE_OK;
PgHdr *pPg; PgHdr *pPg = 0;
const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
/* It is acceptable to use a read-only (mmap) page for any page except
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
** flag was specified by the caller. And so long as the db is not a
** temporary or in-memory database. */
const int bMmapOk = (
(pgno!=1 && pPager->pWal==0 && !pPager->tempFile && !MEMDB)
&& (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY))
);
assert( pPager->eState>=PAGER_READER ); assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
@@ -5190,12 +5218,23 @@ int sqlite3PagerAcquire(
if( pPager->errCode!=SQLITE_OK ){ if( pPager->errCode!=SQLITE_OK ){
rc = pPager->errCode; rc = pPager->errCode;
}else{ }else{
if( pPager->eState==PAGER_READER && pPager->pWal==0 ){
rc = pagerAcquireMapPage(pPager, pgno, &pPg); if( bMmapOk ){
if( rc!=SQLITE_OK ) goto pager_acquire_err; if( pPager->pMap==0 ) rc = pagerMap(pPager);
if( pPg ){ if( rc==SQLITE_OK && pPager->nMap>=((i64)pgno * pPager->pageSize) ){
*ppPage = pPg; if( pPager->eState>PAGER_READER ){
return SQLITE_OK; (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, &pPg);
}
if( pPg ){
assert( rc==SQLITE_OK );
*ppPage = pPg;
return SQLITE_OK;
}else if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
} }
} }
@@ -5433,8 +5472,6 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR ); assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
pPager->subjInMemory = (u8)subjInMemory; pPager->subjInMemory = (u8)subjInMemory;
pagerUnmap(pPager);
if( ALWAYS(pPager->eState==PAGER_READER) ){ if( ALWAYS(pPager->eState==PAGER_READER) ){
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
@@ -5653,13 +5690,11 @@ 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( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED ); 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) );
/* There must not be any outstanding mmap pages at this point */
assert( pPager->nMmapOut==0 );
if( nPagePerSector>1 ){ if( nPagePerSector>1 ){
Pgno nPageCount; /* Total number of pages in database file */ Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */ Pgno pg1; /* First page of the sector pPg is located on. */

View File

@@ -78,6 +78,12 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** Flags that make up the mask passed to sqlite3PagerAcquire().
*/
#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */
#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */
/* /*
** The remainder of this file contains the declarations of the functions ** The remainder of this file contains the declarations of the functions
** that make up the Pager sub-system API. See source code comments for ** that make up the Pager sub-system API. See source code comments for