aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pager.c66
-rw-r--r--src/pcache.c427
-rw-r--r--src/pcache.h22
-rw-r--r--src/test2.c23
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