diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/pager.c | 66 | ||||
-rw-r--r-- | src/pcache.c | 427 | ||||
-rw-r--r-- | src/pcache.h | 22 | ||||
-rw-r--r-- | src/test2.c | 23 |
4 files changed, 209 insertions, 329 deletions
diff --git a/src/pager.c b/src/pager.c index cd3f57426..69c3ee7c3 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.479 2008/08/25 17:23:29 drh Exp $ +** @(#) $Id: pager.c,v 1.480 2008/08/26 18:05:48 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -303,18 +303,6 @@ static const unsigned char aJournalMagic[] = { #define PAGER_MAX_PGNO 2147483647 /* -** The following two macros act as a type of recursive mutex. Their -** only purpose is to provide mutual exclusion between the "normal" -** users of a pager object (the btree.c module) and the user of the -** pagerStress() function (the pcache.c module). While the mutex -** obtained using pagerEnter() is held, the pcache module guarantees -** that the pagerStress() callback will not be invoked from a thread -** other than the holder of the mutex. -*/ -#define pagerEnter(p) (sqlite3PcacheLock(p->pPCache)) -#define pagerLeave(p) (sqlite3PcacheUnlock(p->pPCache)) - -/* ** Return true if page *pPg has already been written to the statement ** journal (or statement snapshot has been created, if *pPg is part ** of an in-memory database). @@ -1956,7 +1944,6 @@ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){ int rc = SQLITE_OK; u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); - pagerEnter(pPager); if( pageSize && pageSize!=pPager->pageSize && !pPager->memDb && sqlite3PcacheRefCount(pPager->pPCache)==0 ){ @@ -1973,7 +1960,6 @@ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){ } } *pPageSize = pPager->pageSize; - pagerLeave(pPager); return rc; } @@ -2042,7 +2028,6 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ int rc = SQLITE_OK; memset(pDest, 0, N); assert(MEMDB||pPager->fd->pMethods||pPager->tempFile); - pagerEnter(pPager); if( pPager->fd->pMethods ){ IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) rc = sqlite3OsRead(pPager->fd, pDest, N, 0); @@ -2050,7 +2035,6 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ rc = SQLITE_OK; } } - pagerLeave(pPager); return rc; } @@ -2067,10 +2051,8 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ i64 n = 0; int rc; assert( pPager!=0 ); - pagerEnter(pPager); if( pPager->errCode ){ rc = pPager->errCode; - pagerLeave(pPager); return rc; } if( pPager->dbSize>=0 ){ @@ -2080,7 +2062,6 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ if( (pPager->fd->pMethods) && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){ pager_error(pPager, rc); - pagerLeave(pPager); return rc; } if( n>0 && n<pPager->pageSize ){ @@ -2101,7 +2082,6 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ if( pnPage ){ *pnPage = n; } - pagerLeave(pPager); return SQLITE_OK; } @@ -2167,7 +2147,6 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ int rc = SQLITE_OK; assert( pPager->state>=PAGER_SHARED || MEMDB ); - pagerEnter(pPager); sqlite3PagerPagecount(pPager, 0); if( pPager->errCode ){ @@ -2188,7 +2167,6 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ } } - pagerLeave(pPager); return rc; } @@ -2207,7 +2185,6 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){ ** to the caller. */ int sqlite3PagerClose(Pager *pPager){ - pagerEnter(pPager); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); @@ -2253,9 +2230,7 @@ Pgno sqlite3PagerPagenumber(DbPage *p){ ** a reference to the page data. */ int sqlite3PagerRef(DbPage *pPg){ - pagerEnter(pPg->pPager); sqlite3PcacheRef(pPg); - pagerLeave(pPg->pPager); return SQLITE_OK; } @@ -2916,9 +2891,7 @@ int sqlite3PagerAcquire( int noContent /* Do not bother reading content from disk if true */ ){ int rc; - pagerEnter(pPager); rc = pagerAcquire(pPager, pgno, ppPage, noContent); - pagerLeave(pPager); return rc; } @@ -2939,13 +2912,11 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ assert( pPager!=0 ); assert( pgno!=0 ); - pagerEnter(pPager); if( (pPager->state!=PAGER_UNLOCK) && (pPager->errCode==SQLITE_OK || pPager->errCode==SQLITE_FULL) ){ sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); } - pagerLeave(pPager); return pPg; } @@ -2961,10 +2932,8 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ int sqlite3PagerUnref(DbPage *pPg){ if( pPg ){ Pager *pPager = pPg->pPager; - pagerEnter(pPager); sqlite3PcacheRelease(pPg); pagerUnlockIfUnused(pPager); - pagerLeave(pPager); } return SQLITE_OK; } @@ -2986,9 +2955,7 @@ static int pager_open_journal(Pager *pPager){ assert( pPager->useJournal ); assert( pPager->pInJournal==0 ); sqlite3PagerPagecount(pPager, 0); - pagerLeave(pPager); pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize); - pagerEnter(pPager); if( pPager->pInJournal==0 ){ rc = SQLITE_NOMEM; goto failed_to_open_journal; @@ -3078,7 +3045,6 @@ failed_to_open_journal: int sqlite3PagerBegin(DbPage *pPg, int exFlag){ Pager *pPager = pPg->pPager; int rc = SQLITE_OK; - pagerEnter(pPager); assert( pPg->nRef>0 ); assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ @@ -3096,7 +3062,6 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ } } if( rc!=SQLITE_OK ){ - pagerLeave(pPager); return rc; } pPager->dirtyCache = 0; @@ -3126,7 +3091,6 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ } } assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); - pagerLeave(pPager); return rc; } @@ -3362,7 +3326,6 @@ int sqlite3PagerWrite(DbPage *pDbPage){ Pager *pPager = pPg->pPager; Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); - pagerEnter(pPager); if( !MEMDB && nPagePerSector>1 ){ Pgno nPageCount; /* Total number of pages in database file */ Pgno pg1; /* First page of the sector pPg is located on. */ @@ -3436,7 +3399,6 @@ int sqlite3PagerWrite(DbPage *pDbPage){ }else{ rc = pager_write(pDbPage); } - pagerLeave(pPager); return rc; } @@ -3480,7 +3442,6 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){ Pager *pPager = pPg->pPager; if( MEMDB ) return; - pagerEnter(pPager); pPg->flags |= PGHDR_ALWAYS_ROLLBACK; if( (pPg->flags&PGHDR_DIRTY) && !pPager->stmtInUse ){ assert( pPager->state>=PAGER_SHARED ); @@ -3502,7 +3463,6 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){ #endif } } - pagerLeave(pPager); } /* @@ -3519,7 +3479,6 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){ void sqlite3PagerDontRollback(DbPage *pPg){ Pager *pPager = pPg->pPager; - pagerEnter(pPager); assert( pPager->state>=PAGER_RESERVED ); /* If the journal file is not open, or DontWrite() has been called on @@ -3529,14 +3488,12 @@ void sqlite3PagerDontRollback(DbPage *pPg){ if( pPager->journalOpen==0 || (pPg->flags&PGHDR_ALWAYS_ROLLBACK) || pPager->alwaysRollback ){ - pagerLeave(pPager); return; } assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */ #ifdef SQLITE_SECURE_DELETE if( pPg->inJournal || (int)pPg->pgno > pPager->origDbSize ){ - pagerLeave(pPager); return; } #endif @@ -3563,7 +3520,6 @@ void sqlite3PagerDontRollback(DbPage *pPg){ } PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager)); IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno)) - pagerLeave(pPager); } @@ -3616,9 +3572,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirect){ */ int sqlite3PagerSync(Pager *pPager){ int rc; - pagerEnter(pPager); rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); - pagerLeave(pPager); return rc; } @@ -3667,7 +3621,6 @@ int sqlite3PagerCommitPhaseOne( PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n", pPager->zFilename, zMaster, nTrunc); - pagerEnter(pPager); /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is a no-op. @@ -3797,7 +3750,6 @@ sync_exit: */ rc = SQLITE_BUSY; } - pagerLeave(pPager); return rc; } @@ -3824,7 +3776,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ assert( pPager->dirtyCache==0 || pPager->journalOpen==0 ); return SQLITE_OK; } - pagerEnter(pPager); PAGERTRACE2("COMMIT %d\n", PAGERID(pPager)); if( MEMDB ){ sqlite3PcacheCommit(pPager->pPCache, 0); @@ -3838,7 +3789,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ rc = pager_end_transaction(pPager, pPager->setMaster); rc = pager_error(pPager, rc); } - pagerLeave(pPager); return rc; } @@ -3857,7 +3807,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int sqlite3PagerRollback(Pager *pPager){ int rc = SQLITE_OK; PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); - pagerEnter(pPager); if( MEMDB ){ sqlite3PcacheRollback(pPager->pPCache, 1); sqlite3PcacheRollback(pPager->pPCache, 0); @@ -3896,7 +3845,6 @@ int sqlite3PagerRollback(Pager *pPager){ */ rc = pager_error(pPager, rc); } - pagerLeave(pPager); return rc; } @@ -3921,7 +3869,6 @@ int sqlite3PagerRefcount(Pager *pPager){ */ int *sqlite3PagerStats(Pager *pPager){ static int a[11]; - pagerEnter(pPager); a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); @@ -3933,7 +3880,6 @@ int *sqlite3PagerStats(Pager *pPager){ a[8] = 0; /* Used to be pPager->nOvfl */ a[9] = pPager->nRead; a[10] = pPager->nWrite; - pagerLeave(pPager); return a; } int sqlite3PagerIsMemdb(Pager *pPager){ @@ -3994,9 +3940,7 @@ stmt_begin_failed: } int sqlite3PagerStmtBegin(Pager *pPager){ int rc; - pagerEnter(pPager); rc = pagerStmtBegin(pPager); - pagerLeave(pPager); return rc; } @@ -4004,7 +3948,6 @@ int sqlite3PagerStmtBegin(Pager *pPager){ ** Commit a statement. */ int sqlite3PagerStmtCommit(Pager *pPager){ - pagerEnter(pPager); if( pPager->stmtInUse ){ PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ @@ -4018,7 +3961,6 @@ int sqlite3PagerStmtCommit(Pager *pPager){ pPager->stmtInUse = 0; } pPager->stmtAutoopen = 0; - pagerLeave(pPager); return SQLITE_OK; } @@ -4027,7 +3969,6 @@ int sqlite3PagerStmtCommit(Pager *pPager){ */ int sqlite3PagerStmtRollback(Pager *pPager){ int rc; - pagerEnter(pPager); if( pPager->stmtInUse ){ PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ @@ -4043,7 +3984,6 @@ int sqlite3PagerStmtRollback(Pager *pPager){ rc = SQLITE_OK; } pPager->stmtAutoopen = 0; - pagerLeave(pPager); return rc; } @@ -4139,8 +4079,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno); IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno)) - pagerEnter(pPager); - pager_get_content(pPg); /* If the journal needs to be sync()ed before page pPg->pgno can @@ -4208,7 +4146,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){ sqlite3BitvecClear(pPager->pInJournal, needSyncPgno); } - pagerLeave(pPager); return rc; } pPager->needSync = 1; @@ -4218,7 +4155,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ sqlite3PagerUnref(pPgHdr); } - pagerLeave(pPager); return SQLITE_OK; } #endif diff --git a/src/pcache.c b/src/pcache.c index fd0f6ee20..09ab28722 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file implements that page cache. ** -** @(#) $Id: pcache.c,v 1.13 2008/08/25 14:49:42 danielk1977 Exp $ +** @(#) $Id: pcache.c,v 1.14 2008/08/26 18:05:48 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -19,23 +19,22 @@ ** A complete page cache is an instance of this structure. */ struct PCache { - PCache *pNextAll, *pPrevAll; /* List of all page caches */ int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ int nHash; /* Number of slots in apHash[] */ int nPage; /* Total number of pages in apHash */ int nMax; /* Configured cache size */ + int nMin; /* Configured minimum cache size */ PgHdr **apHash; /* Hash table for fast lookup by pgno */ int bPurgeable; /* True if pages are on backing store */ void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ void *pStress; /* Argument to xStress */ PgHdr *pClean; /* List of clean pages in use */ - PgHdr *pDirty; /* List of dirty pages */ - int nRef; /* Number of outstanding page refs */ - - int iInUseMM; - int iInUseDB; + PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ + PgHdr *pSynced; /* Last synced page in dirty page list */ + int nRef; /* Number of pinned pages */ + int nPinned; /* Number of pinned and/or dirty pages */ }; /* @@ -59,23 +58,18 @@ struct PgFreeslot { ** pages held by purgable caches to mxPagePurgeable. ** ** The doubly-linked list that runs between pcache.pLruHead and -** pcache.pLruTail contains all pages in the system with a zero -** reference count. The pcache.pLruSynced variable points to the last -** (closest to pcache.pLruTail) entry in this list that does not have -** the PGHDR_NEED_SYNC flag set. This is the page that the pcacheRecycle() -** function will try to recycle. +** pcache.pLruTail contains all clean purgable pages in the system +** with a zero reference count. pcache.pLruTail is the next page to +** be recycled. */ static struct PCacheGlobal { int isInit; /* True when initialized */ - sqlite3_mutex *mutex_mem2; /* static mutex MUTEX_STATIC_MEM2 */ - sqlite3_mutex *mutex_lru; /* static mutex MUTEX_STATIC_LRU */ - PCache *pAll; /* list of all page caches */ - int nPage; /* Number of pages */ - int nPurgeable; /* Number of pages in purgable caches */ - int mxPage; /* Globally configured page maximum */ - int mxPagePurgeable; /* Purgeable page maximum */ - PgHdr *pLruHead, *pLruTail; /* Global LRU list of unused pages */ - PgHdr *pLruSynced; /* Last synced entry in LRU list */ + sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */ + + int nMaxPage; /* Sum of nMaxPage for purgeable caches */ + int nMinPage; /* Sum of nMinPage for purgeable caches */ + int nCurrentPage; /* Number of purgeable pages allocated */ + PgHdr *pLruHead, *pLruTail; /* LRU list of unused clean pgs */ /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */ int szSlot; /* Size of each free slot */ @@ -85,31 +79,17 @@ static struct PCacheGlobal { /* ** All global variables used by this module (most of which are grouped -** together in global structure "pcache" above) except the list of all -** pager-caches starting with pcache.pAll, are protected by the static +** together in global structure "pcache" above) are protected by the static ** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in -** variable "pcache.mutex_lru". +** variable "pcache.mutex". ** ** Access to the contents of the individual PCache structures is not ** protected. It is the job of the caller to ensure that these structures -** are accessed in a thread-safe manner. However, this module provides the -** functions sqlite3PcacheLock() and sqlite3PcacheUnlock() that may be used -** by the caller to increment/decrement a lock-count on an individual -** pager-cache object. This module guarantees that the xStress() callback -** will not be invoked on a pager-cache with a non-zero lock-count except -** from within a call to sqlite3PcacheFetch() on the same pager. A call -** to sqlite3PcacheLock() may block if such an xStress() call is currently -** underway. -** -** Before the xStress callback of a pager-cache (PCache) is invoked, the -** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained. -** -** Deadlock within the module is avoided by never blocking on the MEM2 -** mutex while the LRU mutex is held. +** are accessed in a thread-safe manner. */ -#define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex_lru) -#define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex_lru) +#define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex) +#define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex) /********************************** Linked List Management ********************/ @@ -131,6 +111,40 @@ static int pcacheCheckHashCount(PCache *pCache){ assert( nPage==pCache->nPage ); return 1; } + +/* +** Based on the current value of PCache.nRef and the contents of the +** PCache.pDirty list, return the expected value of the PCache.nPinned +** counter. This is only used in debugging builds, as follows: +** +** assert( pCache->nPinned==pcachePinnedCount(pCache) ); +*/ +static int pcachePinnedCount(PCache *pCache){ + PgHdr *p; + int nPinned = pCache->nRef; + for(p=pCache->pDirty; p; p=p->pNext){ + if( p->nRef==0 ){ + nPinned++; + } + } + return nPinned; +} + +/* +** Check that the pCache->pSynced variable is set correctly. If it +** is not, either fail an assert or return zero. Otherwise, return +** non-zero. This is only used in debugging builds, as follows: +** +** assert( pcacheCheckSynced(pCache) ); +*/ +static int pcacheCheckSynced(PCache *pCache){ + PgHdr *p = pCache->pDirtyTail; + for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){ + assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) ); + } + return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0); +} + #endif /* @@ -205,6 +219,9 @@ static int pcacheResizeHash(PCache *pCache, int nHash){ ** *ppHead is either PCache.pClean or PCache.pDirty. */ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){ + int isDirtyList = (ppHead==&pPage->pCache->pDirty); + assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty ); + if( pPage->pPrev ){ pPage->pPrev->pNext = pPage->pNext; }else{ @@ -214,6 +231,21 @@ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){ if( pPage->pNext ){ pPage->pNext->pPrev = pPage->pPrev; } + + if( isDirtyList ){ + PCache *pCache = pPage->pCache; + assert( pPage->pNext || pCache->pDirtyTail==pPage ); + if( !pPage->pNext ){ + pCache->pDirtyTail = pPage->pPrev; + } + if( pCache->pSynced==pPage ){ + PgHdr *pSynced = pPage->pPrev; + while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ + pSynced = pSynced->pPrev; + } + pCache->pSynced = pSynced; + } + } } /* @@ -221,32 +253,44 @@ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){ ** *ppHead is either PCache.pClean or PCache.pDirty. */ static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){ + int isDirtyList = (ppHead==&pPage->pCache->pDirty); + assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty ); + if( (*ppHead) ){ (*ppHead)->pPrev = pPage; } pPage->pNext = *ppHead; pPage->pPrev = 0; *ppHead = pPage; + + if( isDirtyList ){ + PCache *pCache = pPage->pCache; + if( !pCache->pDirtyTail ){ + assert( pPage->pNext==0 ); + pCache->pDirtyTail = pPage; + } + if( !pCache->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ + pCache->pSynced = pPage; + } + } } /* ** Remove a page from the global LRU list */ static void pcacheRemoveFromLruList(PgHdr *pPage){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); + assert( (pPage->flags&PGHDR_DIRTY)==0 ); if( pPage->pCache->bPurgeable==0 ) return; - if( pPage==pcache.pLruSynced ){ - PgHdr *p; - for(p=pPage->pPrevLru; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru); - pcache.pLruSynced = p; - } if( pPage->pNextLru ){ + assert( pcache.pLruTail!=pPage ); pPage->pNextLru->pPrevLru = pPage->pPrevLru; }else{ assert( pcache.pLruTail==pPage ); pcache.pLruTail = pPage->pPrevLru; } if( pPage->pPrevLru ){ + assert( pcache.pLruHead!=pPage ); pPage->pPrevLru->pNextLru = pPage->pNextLru; }else{ assert( pcache.pLruHead==pPage ); @@ -261,7 +305,8 @@ static void pcacheRemoveFromLruList(PgHdr *pPage){ ** to the end of the LRU list so that it will be the next to be recycled. */ static void pcacheAddToLruList(PgHdr *pPage){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); + assert( (pPage->flags&PGHDR_DIRTY)==0 ); if( pPage->pCache->bPurgeable==0 ) return; if( pcache.pLruTail && (pPage->flags & PGHDR_REUSE_UNLIKELY)!=0 ){ /* If reuse is unlikely. Put the page at the end of the LRU list @@ -273,9 +318,6 @@ static void pcacheAddToLruList(PgHdr *pPage){ pcache.pLruTail->pNextLru = pPage; pcache.pLruTail = pPage; pPage->flags &= ~PGHDR_REUSE_UNLIKELY; - if( 0==(pPage->flags&PGHDR_NEED_SYNC) ){ - pcache.pLruSynced = pPage; - } }else{ /* If reuse is possible. the page goes at the beginning of the LRU ** list so that it will be the last to be recycled. @@ -289,9 +331,6 @@ static void pcacheAddToLruList(PgHdr *pPage){ if( pcache.pLruTail==0 ){ pcache.pLruTail = pPage; } - if( pcache.pLruSynced==0 && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ - pcache.pLruSynced = pPage; - } } } @@ -323,7 +362,7 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ ** in the page cache memory pool, go to the general purpose memory allocator. */ void *pcacheMalloc(int sz, PCache *pCache){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); if( sz<=pcache.szSlot && pcache.pFree ){ PgFreeslot *p = pcache.pFree; pcache.pFree = p->pNext; @@ -342,9 +381,7 @@ void *pcacheMalloc(int sz, PCache *pCache){ ** the global LRU mutex. */ pcacheExitGlobal(); - sqlite3PcacheUnlock(pCache); p = sqlite3Malloc(sz); - sqlite3PcacheLock(pCache); pcacheEnterGlobal(); if( p ){ @@ -366,7 +403,7 @@ void *sqlite3PageMalloc(sz){ ** Release a pager memory allocation */ void pcacheFree(void *p){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); if( p==0 ) return; if( p>=pcache.pStart && p<pcache.pEnd ){ PgFreeslot *pSlot; @@ -392,17 +429,15 @@ void sqlite3PageFree(void *p){ static PgHdr *pcachePageAlloc(PCache *pCache){ PgHdr *p; int sz = sizeof(*p) + pCache->szPage + pCache->szExtra; - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); p = pcacheMalloc(sz, pCache); if( p==0 ) return 0; memset(p, 0, sizeof(PgHdr)); p->pData = (void*)&p[1]; p->pExtra = (void*)&((char*)p->pData)[pCache->szPage]; - pcache.nPage++; if( pCache->bPurgeable ){ - pcache.nPurgeable++; + pcache.nCurrentPage++; } - return p; } @@ -410,10 +445,9 @@ static PgHdr *pcachePageAlloc(PCache *pCache){ ** Deallocate a page */ static void pcachePageFree(PgHdr *p){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); - pcache.nPage--; + assert( sqlite3_mutex_held(pcache.mutex) ); if( p->pCache->bPurgeable ){ - pcache.nPurgeable--; + pcache.nCurrentPage--; } pcacheFree(p->apSave[0]); pcacheFree(p->apSave[1]); @@ -426,7 +460,7 @@ static void pcachePageFree(PgHdr *p){ ** the argument is passed to pcachePageFree(). */ static int pcachePageSize(PgHdr *p){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); assert( !pcache.pStart ); assert( p->apSave[0]==0 ); assert( p->apSave[1]==0 ); @@ -435,58 +469,30 @@ static int pcachePageSize(PgHdr *p){ } #endif -static int pcacheRecyclePage(PgHdr *p, PCache *pCache){ - assert( sqlite3_mutex_held(pcache.mutex_lru) ); - assert( sqlite3_mutex_held(pcache.mutex_mem2) ); - - PCache *pC = p->pCache; - assert( pC->iInUseMM==0 ); - pC->iInUseMM = 1; - if( pC->xStress && (pC->iInUseDB==0 || pC==pCache) ){ - pcacheExitGlobal(); - pC->xStress(pC->pStress, p); - pcacheEnterGlobal(); - } - pC->iInUseMM = 0; - - return (p->flags&PGHDR_DIRTY); -} - /* -** Recycle a page from the global LRU list. If no page can be recycled, -** return NULL. Otherwise, the pointer returned points to a PgHdr -** object that has been removed from all lists and hash tables in -** which is was referenced. The caller may reuse the allocation directly -** or may pass it to pcachePageFree() to return the memory to the heap -** (or pcache.pFree list). -*/ -static PgHdr *pcacheRecycle(PCache *pCache){ +** Attempt to 'recycle' a page from the global LRU list. Only clean, +** unreferenced pages from purgeable caches are eligible for recycling. +** +** This function removes page pcache.pLruTail from the global LRU list, +** and from the hash-table and PCache.pClean list of the owner pcache. +** There should be no other references to the page. +** +** A pointer to the recycled page is returned, or NULL if no page is +** eligible for recycling. +*/ +static PgHdr *pcacheRecyclePage(){ PgHdr *p = 0; + assert( sqlite3_mutex_held(pcache.mutex) ); - assert( pcache.isInit ); - assert( sqlite3_mutex_held(pcache.mutex_lru) ); - - if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){ - p = pcache.pLruSynced; - while( p && (p->flags&PGHDR_DIRTY) && pcacheRecyclePage(p, pCache) ){ - do { p = p->pPrevLru; } while( p && (p->flags&PGHDR_NEED_SYNC) ); - } - if( !p ){ - p = pcache.pLruTail; - while( p && (p->flags&PGHDR_DIRTY) && pcacheRecyclePage(p, pCache) ){ - do { p = p->pPrevLru; } while( p && 0==(p->flags&PGHDR_NEED_SYNC) ); - } - } - sqlite3_mutex_leave(pcache.mutex_mem2); - } - - if( p ){ + if( (p=pcache.pLruTail) ){ + assert( (p->flags&PGHDR_DIRTY)==0 ); pcacheRemoveFromLruList(p); pcacheRemoveFromHash(p); pcacheRemoveFromList(&p->pCache->pClean, p); /* If the always-rollback flag is set on the page being recycled, set - ** the always-rollback flag on the corresponding pager. + ** the always-rollback flag on the corresponding pager. TODO: This is + ** a thread-safety problem. */ if( p->flags&PGHDR_ALWAYS_ROLLBACK ){ assert(p->pPager); @@ -509,21 +515,45 @@ static PgHdr *pcacheRecycleOrAlloc(PCache *pCache){ int szPage = pCache->szPage; int szExtra = pCache->szExtra; - int bPurg = pCache->bPurgeable; assert( pcache.isInit ); - assert( sqlite3_mutex_notheld(pcache.mutex_lru) ); + assert( sqlite3_mutex_notheld(pcache.mutex) ); pcacheEnterGlobal(); - if( (pcache.mxPage && pcache.nPage>=pcache.mxPage) - || (!pcache.mxPage && bPurg && pcache.nPurgeable>=pcache.mxPagePurgeable) + /* If we have reached the limit for pinned/dirty pages, and there is at + ** least one dirty page, invoke the xStress callback to cause a page to + ** become clean. + */ + assert( pCache->nPinned==pcachePinnedCount(pCache) ); + assert( pcacheCheckSynced(pCache) ); + if( pCache->xStress + && pCache->pDirty + && pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage) ){ - /* If the above test succeeds, then try to obtain a buffer by recycling - ** an existing page. */ - p = pcacheRecycle(pCache); + PgHdr *pPg; + assert(pCache->pDirtyTail); + + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + pPg=pPg->pPrev + ); + if( !pPg ){ + for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pPrev); + } + if( pPg ){ + pcacheExitGlobal(); + pCache->xStress(pCache->pStress, pPg); + pcacheEnterGlobal(); + } + } + + /* If the global page limit has been reached, try to recycle a page. */ + if( pcache.nCurrentPage>=pcache.nMaxPage ){ + p = pcacheRecyclePage(); } + /* If a page has been recycled but it is the wrong size, free it. */ if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){ pcachePageFree(p); p = 0; @@ -546,9 +576,8 @@ int sqlite3PcacheInitialize(void){ assert( pcache.isInit==0 ); memset(&pcache, 0, sizeof(pcache)); if( sqlite3Config.bCoreMutex ){ - pcache.mutex_lru = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); - pcache.mutex_mem2 = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); - if( pcache.mutex_lru==0 || pcache.mutex_mem2==0 ){ + pcache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); + if( pcache.mutex==0 ){ return SQLITE_NOMEM; } } @@ -586,21 +615,14 @@ void sqlite3PcacheOpen( p->xStress = xStress; p->pStress = pStress; p->nMax = 100; + p->nMin = 20; + pcacheEnterGlobal(); if( bPurgeable ){ - pcacheEnterGlobal(); - pcache.mxPagePurgeable += p->nMax; - pcacheExitGlobal(); + pcache.nMaxPage += p->nMax; + pcache.nMinPage += p->nMin; } - /* Add the new pager-cache to the list of caches starting at pcache.pAll */ - pcacheEnterGlobal(); - p->pNextAll = pcache.pAll; - if( pcache.pAll ){ - pcache.pAll->pPrevAll = p; - } - p->pPrevAll = 0; - pcache.pAll = p; pcacheExitGlobal(); } @@ -626,21 +648,23 @@ int sqlite3PcacheFetch( assert( pcache.isInit ); assert( pCache!=0 ); assert( pgno>0 ); - assert( pCache->iInUseDB || pCache->iInUseMM ); + assert( pCache->nPinned==pcachePinnedCount(pCache) ); /* Search the hash table for the requested page. Exit early if it is found. */ if( pCache->apHash ){ u32 h = pgno % pCache->nHash; for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){ if( pPage->pgno==pgno ){ - if( pPage->nRef==0 /* && (pPage->flags & PGHDR_DIRTY)==0 */ ){ - pcacheEnterGlobal(); - pcacheRemoveFromLruList(pPage); - pcacheExitGlobal(); - } - if( (pPage->nRef++)==0 ){ + if( pPage->nRef==0 ){ + if( 0==(pPage->flags&PGHDR_DIRTY) ){ + pcacheEnterGlobal(); + pcacheRemoveFromLruList(pPage); + pcacheExitGlobal(); + pCache->nPinned++; + } pCache->nRef++; } + pPage->nRef++; *ppPage = pPage; return SQLITE_OK; } @@ -668,12 +692,14 @@ int sqlite3PcacheFetch( pPage->pCache = pCache; pPage->nRef = 1; pCache->nRef++; + pCache->nPinned++; pcacheAddToList(&pCache->pClean, pPage); pcacheAddToHash(pPage); }else{ *ppPage = 0; } + assert( pCache->nPinned==pcachePinnedCount(pCache) ); return SQLITE_OK; } @@ -683,20 +709,23 @@ int sqlite3PcacheFetch( */ void sqlite3PcacheRelease(PgHdr *p){ assert( p->nRef>0 ); - assert( p->pCache->iInUseDB || p->pCache->iInUseMM ); p->nRef--; if( p->nRef==0 ){ PCache *pCache = p->pCache; - pCache->nRef--; if( p->pCache->xDestroy ){ p->pCache->xDestroy(p); } -#if 0 - if( (p->flags & PGHDR_DIRTY)!=0 ) return; -#endif - pcacheEnterGlobal(); - pcacheAddToLruList(p); - pcacheExitGlobal(); + pCache->nRef--; + if( (p->flags&PGHDR_DIRTY)==0 ){ + pCache->nPinned--; + pcacheEnterGlobal(); + pcacheAddToLruList(p); + pcacheExitGlobal(); + }else{ + /* Move the page to the head of the caches dirty list. */ + pcacheRemoveFromList(&pCache->pDirty, p); + pcacheAddToList(&pCache->pDirty, p); + } } } @@ -711,10 +740,10 @@ void sqlite3PcacheRef(PgHdr *p){ */ void sqlite3PcacheDrop(PgHdr *p){ PCache *pCache; - assert( p->pCache->iInUseDB ); assert( p->nRef==1 ); pCache = p->pCache; pCache->nRef--; + pCache->nPinned--; if( p->flags & PGHDR_DIRTY ){ pcacheRemoveFromList(&pCache->pDirty, p); }else{ @@ -732,7 +761,6 @@ void sqlite3PcacheDrop(PgHdr *p){ */ void sqlite3PcacheMakeDirty(PgHdr *p){ PCache *pCache; - assert( p->pCache->iInUseDB ); p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_DIRTY ) return; assert( (p->flags & PGHDR_DIRTY)==0 ); @@ -749,14 +777,20 @@ void sqlite3PcacheMakeDirty(PgHdr *p){ */ void sqlite3PcacheMakeClean(PgHdr *p){ PCache *pCache; - assert( p->pCache->iInUseDB || p->pCache->iInUseMM ); if( (p->flags & PGHDR_DIRTY)==0 ) return; assert( p->apSave[0]==0 && p->apSave[1]==0 ); assert( p->flags & PGHDR_DIRTY ); pCache = p->pCache; pcacheRemoveFromList(&pCache->pDirty, p); + pcacheEnterGlobal(); pcacheAddToList(&pCache->pClean, p); p->flags &= ~PGHDR_DIRTY; + if( p->nRef==0 ){ + pcacheAddToLruList(p); + pCache->nPinned--; + } + assert( pCache->nPinned==pcachePinnedCount(pCache) ); + pcacheExitGlobal(); } /* @@ -764,15 +798,19 @@ void sqlite3PcacheMakeClean(PgHdr *p){ */ void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; - assert( pCache->iInUseDB ); pcacheEnterGlobal(); while( (p = pCache->pDirty)!=0 ){ assert( p->apSave[0]==0 && p->apSave[1]==0 ); pcacheRemoveFromList(&pCache->pDirty, p); - pcacheAddToList(&pCache->pClean, p); p->flags &= ~PGHDR_DIRTY; + pcacheAddToList(&pCache->pClean, p); + if( p->nRef==0 ){ + pcacheAddToLruList(p); + pCache->nPinned--; + } } sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY); + assert( pCache->nPinned==pcachePinnedCount(pCache) ); pcacheExitGlobal(); } @@ -782,7 +820,7 @@ void sqlite3PcacheCleanAll(PCache *pCache){ ** flag set. */ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ - assert( p->pCache->iInUseDB ); + assert( p->nRef>0 ); pcacheRemoveFromHash(p); p->pgno = newPgno; if( newPgno==0 ){ @@ -799,20 +837,11 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ } /* -** Set the global maximum number of pages. Return the previous value. -*/ -void sqlite3PcacheGlobalMax(int mx){ - pcacheEnterGlobal(); - pcache.mxPage = mx; - pcacheExitGlobal(); -} - -/* ** Remove all content from a page cache */ void pcacheClear(PCache *pCache){ PgHdr *p, *pNext; - assert( sqlite3_mutex_held(pcache.mutex_lru) ); + assert( sqlite3_mutex_held(pcache.mutex) ); for(p=pCache->pClean; p; p=pNext){ pNext = p->pNext; pcacheRemoveFromLruList(p); @@ -820,12 +849,13 @@ void pcacheClear(PCache *pCache){ } for(p=pCache->pDirty; p; p=pNext){ pNext = p->pNext; - pcacheRemoveFromLruList(p); pcachePageFree(p); } pCache->pClean = 0; pCache->pDirty = 0; + pCache->pDirtyTail = 0; pCache->nPage = 0; + pCache->nPinned = 0; memset(pCache->apHash, 0, pCache->nHash*sizeof(pCache->apHash[0])); } @@ -836,7 +866,6 @@ void pcacheClear(PCache *pCache){ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ PgHdr *p, *pNext; PgHdr *pDirty = pCache->pDirty; - assert( pCache->iInUseDB ); pcacheEnterGlobal(); for(p=pCache->pClean; p||pDirty; p=pNext){ if( !p ){ @@ -849,10 +878,11 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ pcacheRemoveFromHash(p); if( p->flags&PGHDR_DIRTY ){ pcacheRemoveFromList(&pCache->pDirty, p); + pCache->nPinned--; }else{ pcacheRemoveFromList(&pCache->pClean, p); + pcacheRemoveFromLruList(p); } - pcacheRemoveFromLruList(p); pcachePageFree(p); }else{ /* If there are references to the page, it cannot be freed. In this @@ -870,31 +900,16 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ ** Close a cache. */ void sqlite3PcacheClose(PCache *pCache){ - assert( pCache->iInUseDB==1 ); pcacheEnterGlobal(); /* Free all the pages used by this pager and remove them from the LRU list. */ pcacheClear(pCache); if( pCache->bPurgeable ){ - pcache.mxPagePurgeable -= pCache->nMax; + pcache.nMaxPage -= pCache->nMax; + pcache.nMinPage -= pCache->nMin; } sqlite3_free(pCache->apHash); - /* Now remove the pager-cache structure itself from the list of - ** all such structures headed by pcache.pAll. - */ - assert(pCache==pcache.pAll || pCache->pPrevAll); - assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache); - assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache); - if( pCache->pPrevAll ){ - pCache->pPrevAll->pNextAll = pCache->pNextAll; - }else{ - pcache.pAll = pCache->pNextAll; - } - if( pCache->pNextAll ){ - pCache->pNextAll->pPrevAll = pCache->pPrevAll; - } - pcacheExitGlobal(); } @@ -910,7 +925,6 @@ void sqlite3PcacheClose(PCache *pCache){ int sqlite3PcachePreserve(PgHdr *p, int idJournal){ void *x; int sz; - assert( p->pCache->iInUseDB ); assert( p->pCache->bPurgeable==0 ); if( !p->apSave[idJournal] ){ sz = p->pCache->szPage; @@ -926,7 +940,6 @@ int sqlite3PcachePreserve(PgHdr *p, int idJournal){ */ void sqlite3PcacheCommit(PCache *pCache, int idJournal){ PgHdr *p; - assert( pCache->iInUseDB ); pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */ for(p=pCache->pDirty; p; p=p->pNext){ if( p->apSave[idJournal] ){ @@ -943,7 +956,6 @@ void sqlite3PcacheCommit(PCache *pCache, int idJournal){ void sqlite3PcacheRollback(PCache *pCache, int idJournal){ PgHdr *p; int sz; - assert( pCache->iInUseDB ); pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */ sz = pCache->szPage; for(p=pCache->pDirty; p; p=p->pNext){ @@ -961,7 +973,6 @@ void sqlite3PcacheRollback(PCache *pCache, int idJournal){ */ void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){ PgHdr *p; - assert( pCache->iInUseDB || pCache->iInUseMM ); for(p=pCache->pDirty; p; p=p->pNext){ assert( (p->flags&trueMask)==trueMask ); assert( (p->flags&falseMask)==0 ); @@ -976,7 +987,6 @@ void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){ ** Discard the contents of the cache. */ int sqlite3PcacheClear(PCache *pCache){ - assert( pCache->iInUseDB ); assert(pCache->nRef==0); pcacheEnterGlobal(); pcacheClear(pCache); @@ -1063,7 +1073,6 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ */ PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ PgHdr *p; - assert( pCache->iInUseDB ); for(p=pCache->pDirty; p; p=p->pNext){ p->pDirty = p->pNext; } @@ -1081,7 +1090,6 @@ int sqlite3PcacheRefCount(PCache *pCache){ ** Return the total number of pages in the cache. */ int sqlite3PcachePagecount(PCache *pCache){ - assert( pCache->iInUseDB || pCache->iInUseMM ); assert( pCache->nPage>=0 ); return pCache->nPage; } @@ -1094,7 +1102,6 @@ int sqlite3PcachePagecount(PCache *pCache){ */ void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){ PgHdr *p; - assert( pCache->iInUseDB || pCache->iInUseMM ); for(p=pCache->pClean; p; p=p->pNext){ xIter(p); } @@ -1111,13 +1118,11 @@ void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){ PgHdr *p; assert( (orMask&PGHDR_NEED_SYNC)==0 ); - assert( pCache->iInUseDB || pCache->iInUseMM ); /* Obtain the global mutex before modifying any PgHdr.flags variables ** or traversing the LRU list. */ pcacheEnterGlobal(); - assert( sqlite3_mutex_held(pcache.mutex_lru) ); for(p=pCache->pDirty; p; p=p->pNext){ p->flags = (p->flags&andMask)|orMask; @@ -1127,8 +1132,11 @@ void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){ } if( 0==(andMask&PGHDR_NEED_SYNC) ){ - for(p=pcache.pLruTail; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru); - pcache.pLruSynced = p; + PgHdr *pSynced = pCache->pDirtyTail; + while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ + pSynced = pSynced->pPrev; + } + pCache->pSynced = pSynced; } pcacheExitGlobal(); @@ -1150,40 +1158,13 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ } if( pCache->bPurgeable ){ pcacheEnterGlobal(); - pcache.mxPagePurgeable -= pCache->nMax; - pcache.mxPagePurgeable += mxPage; + pcache.nMaxPage -= pCache->nMax; + pcache.nMaxPage += mxPage; pcacheExitGlobal(); } pCache->nMax = mxPage; } -/* -** Lock a pager-cache. -*/ -void sqlite3PcacheLock(PCache *pCache){ - if( pCache ){ - assert( sqlite3_mutex_notheld(pcache.mutex_lru) ); - pCache->iInUseDB++; - if( pCache->iInUseMM && pCache->iInUseDB==1 ){ - pCache->iInUseDB = 0; - sqlite3_mutex_enter(pcache.mutex_mem2); - assert( pCache->iInUseMM==0 && pCache->iInUseDB==0 ); - pCache->iInUseDB = 1; - sqlite3_mutex_leave(pcache.mutex_mem2); - } - } -} - -/* -** Unlock a pager-cache. -*/ -void sqlite3PcacheUnlock(PCache *pCache){ - if( pCache ){ - pCache->iInUseDB--; - assert( pCache->iInUseDB>=0 ); - } -} - #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory @@ -1199,7 +1180,7 @@ int sqlite3PcacheReleaseMemory(int nReq){ if( pcache.pStart==0 ){ PgHdr *p; pcacheEnterGlobal(); - while( (nReq<0 || nFree<nReq) && (p=pcacheRecycle(0)) ){ + while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){ nFree += pcachePageSize(p); pcachePageFree(p); } diff --git a/src/pcache.h b/src/pcache.h index 0a59d1d8b..0fc3b7df3 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -12,7 +12,7 @@ ** This header file defines the interface that the sqlite page cache ** subsystem. ** -** @(#) $Id: pcache.h,v 1.5 2008/08/23 18:53:08 danielk1977 Exp $ +** @(#) $Id: pcache.h,v 1.6 2008/08/26 18:05:48 danielk1977 Exp $ */ #ifndef _PCACHE_H_ @@ -101,12 +101,6 @@ void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */ /* Change a page number. Used by incr-vacuum. */ void sqlite3PcacheMove(PgHdr*, Pgno); -/* Set a global maximum page count for all page caches. -** If the sum of individual cache maxes exceed the global max, the -** individuals are scaled down proportionally. -*/ -void sqlite3PcacheGlobalMax(int N); - /* Remove all pages with pgno>x. Reset the cache if x==0 */ void sqlite3PcacheTruncate(PCache*, Pgno x); @@ -148,10 +142,7 @@ int sqlite3PcachePagecount(PCache*); */ void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)); -/* Set and get the suggested cache-size for the specified pager-cache. If -** a global maximum on the number of pages cached by the system is -** configured via the sqlite3PcacheGlobalMax() API, then the suggested -** cache-sizes are not used at all. +/* Set and get the suggested cache-size for the specified pager-cache. ** ** If no global maximum is configured, then the system attempts to limit ** the total number of pages cached by purgeable pager-caches to the sum @@ -160,14 +151,7 @@ void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)); int sqlite3PcacheGetCachesize(PCache *); void sqlite3PcacheSetCachesize(PCache *, int); -/* Lock and unlock a pager-cache object. The PcacheLock() function may -** block if the lock is temporarily available. While a pager-cache is locked, -** the system guarantees that any configured xStress() callback will not -** be invoked by any thread other than the one holding the lock. -*/ -void sqlite3PcacheLock(PCache *); -void sqlite3PcacheUnlock(PCache *); - +/* Try to return memory used by the pcache module to the main memory heap */ int sqlite3PcacheReleaseMemory(int); #endif /* _PCACHE_H_ */ diff --git a/src/test2.c b/src/test2.c index 18b128b7b..5188257d4 100644 --- a/src/test2.c +++ b/src/test2.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test2.c,v 1.60 2008/08/20 14:49:25 danielk1977 Exp $ +** $Id: test2.c,v 1.61 2008/08/26 18:05:48 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -383,26 +383,6 @@ static int page_lookup( } /* -** Usage: pcache_global_max NPAGE -*/ -static int pcache_global_max( - void *NotUsed, - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int argc, /* Number of arguments */ - const char **argv /* Text of each argument */ -){ - int nPage; - if( argc!=2 ){ - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " NPAGE\"", 0); - return TCL_ERROR; - } - if( Tcl_GetInt(interp, argv[1], &nPage) ) return TCL_ERROR; - sqlite3PcacheGlobalMax(nPage); - return TCL_OK; -} - -/* ** Usage: pager_truncate ID PGNO */ static int pager_truncate( @@ -650,7 +630,6 @@ int Sqlitetest2_Init(Tcl_Interp *interp){ { "page_write", (Tcl_CmdProc*)page_write }, { "page_number", (Tcl_CmdProc*)page_number }, { "pager_truncate", (Tcl_CmdProc*)pager_truncate }, - { "pcache_global_max", (Tcl_CmdProc*)pcache_global_max }, #ifndef SQLITE_OMIT_DISKIO { "fake_big_file", (Tcl_CmdProc*)fake_big_file }, #endif |