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

@@ -658,6 +658,7 @@ struct Pager {
void *pMap; /* Memory mapped prefix of database file */
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 */
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( currentSize>newSize ){
rc = sqlite3OsTruncate(pPager->fd, newSize);
if( newSize<pPager->nMapValid ){
pPager->nMapValid = newSize;
}
}else if( (currentSize+szPage)<=newSize ){
char *pTmp = pPager->pTmpSpace;
memset(pTmp, 0, szPage);
@@ -3818,6 +3822,7 @@ static int pagerUnmap(Pager *pPager){
munmap(pPager->pMap, pPager->nMap);
pPager->pMap = 0;
pPager->nMap = 0;
pPager->nMapValid = 0;
}
return SQLITE_OK;
}
@@ -3839,7 +3844,7 @@ static int pagerMap(Pager *pPager){
return SQLITE_IOERR;
}
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( pgno!=1 && pPager->pMap && pPager->nMap>=((i64)pgno*pPager->pageSize) ){
if( pgno!=1 && pPager->pMap
&& pPager->nMapValid>=((i64)pgno*pPager->pageSize)
){
PgHdr *p;
if( pPager->pFree ){
p = pPager->pFree;
@@ -5035,9 +5042,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
);
}
if( !pPager->tempFile
&& (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0)
){
if( !pPager->tempFile && (
pPager->pBackup
|| sqlite3PcachePagecount(pPager->pPCache)>0
|| pPager->pMap
)){
/* The shared-lock has just been acquired on the database file
** and there are already pages in the cache (from a previous
** 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 ){
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);
}
}
@@ -5173,10 +5191,20 @@ int sqlite3PagerAcquire(
Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */
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;
PgHdr *pPg;
int rc = SQLITE_OK;
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( assert_pager_state(pPager) );
@@ -5190,12 +5218,23 @@ int sqlite3PagerAcquire(
if( pPager->errCode!=SQLITE_OK ){
rc = pPager->errCode;
}else{
if( pPager->eState==PAGER_READER && pPager->pWal==0 ){
rc = pagerAcquireMapPage(pPager, pgno, &pPg);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
if( pPg ){
*ppPage = pPg;
return SQLITE_OK;
if( bMmapOk ){
if( pPager->pMap==0 ) rc = pagerMap(pPager);
if( rc==SQLITE_OK && pPager->nMap>=((i64)pgno * pPager->pageSize) ){
if( pPager->eState>PAGER_READER ){
(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 );
pPager->subjInMemory = (u8)subjInMemory;
pagerUnmap(pPager);
if( ALWAYS(pPager->eState==PAGER_READER) ){
assert( pPager->pInJournal==0 );
@@ -5653,13 +5690,11 @@ int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPager) );
/* There must not be any outstanding mmap pages at this point */
assert( pPager->nMmapOut==0 );
if( nPagePerSector>1 ){
Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */