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:
19
manifest
19
manifest
@@ -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
|
||||||
|
@@ -1 +1 @@
|
|||||||
6f21d9cbf5d457e63a7282015a89ae785526cf6d
|
b387e2f9d24dccac1fd040e309f6fc7ec1cfffba
|
100
src/btree.c
100
src/btree.c
@@ -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;
|
||||||
|
73
src/pager.c
73
src/pager.c
@@ -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. */
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user