/* ** Dereference a page. When the reference count reaches zero, ** move the page to the LRU list if it is clean. */ void sqlite3PcacheRelease(PgHdr *p) { assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ) { PCache *pCache = p->pCache; if( p->pCache->xDestroy ) { p->pCache->xDestroy(p); } pCache->nRef--; if( (p->flags&PGHDR_DIRTY)==0 ) { pCache->nPinned--; pcacheEnterMutex(); if( pcache.nCurrentPage>pcache.nMaxPage ) { pcacheRemoveFromList(&pCache->pClean, p); pcacheRemoveFromHash(p); pcachePageFree(p); } else { pcacheAddToLruList(p); } pcacheExitMutex(); } else { /* Move the page to the head of the caches dirty list. */ pcacheRemoveFromList(&pCache->pDirty, p); pcacheAddToList(&pCache->pDirty, p); } } }
/* ** Drop every cache entry whose page number is greater than "pgno". */ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ PgHdr *p, *pNext; PgHdr *pDirty = pCache->pDirty; pcacheEnterMutex(); for(p=pCache->pClean; p||pDirty; p=pNext){ if( !p ){ p = pDirty; pDirty = 0; } pNext = p->pNext; if( p->pgno>pgno ){ if( p->nRef==0 ){ pcacheRemoveFromHash(p); if( p->flags&PGHDR_DIRTY ){ pcacheRemoveFromList(&pCache->pDirty, p); pCache->nPinned--; }else{ pcacheRemoveFromList(&pCache->pClean, p); pcacheRemoveFromLruList(p); } pcachePageFree(p); }else{ /* If there are references to the page, it cannot be freed. In this ** case, zero the page content instead. */ memset(p->pData, 0, pCache->szPage); } } } pcacheExitMutex(); }
static void pcacheMakeClean(PgHdr *p){ PCache *pCache = p->pCache; assert( p->flags & PGHDR_DIRTY ); pcacheRemoveFromList(&pCache->pDirty, p); pcacheAddToList(&pCache->pClean, p); p->flags &= ~PGHDR_DIRTY; if( p->nRef==0 ){ pcacheAddToLruList(p); pCache->nPinned--; } expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); }
/* ** Make sure the page is marked as dirty. If it isn't dirty already, ** make it so. */ void sqlite3PcacheMakeDirty(PgHdr *p){ PCache *pCache; p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_DIRTY ) return; assert( (p->flags & PGHDR_DIRTY)==0 ); assert( p->nRef>0 ); pCache = p->pCache; pcacheEnterMutex(); pcacheRemoveFromList(&pCache->pClean, p); pcacheAddToList(&pCache->pDirty, p); pcacheExitMutex(); p->flags |= PGHDR_DIRTY; }
/* ** Drop a page from the cache. There must be exactly one reference to the ** page. This function deletes that reference, so after it returns the ** page pointed to by p is invalid. */ void sqlite3PcacheDrop(PgHdr *p){ PCache *pCache; assert( p->nRef==1 ); assert( 0==(p->flags&PGHDR_DIRTY) ); pCache = p->pCache; pCache->nRef--; pCache->nPinned--; pcacheEnterMutex(); pcacheRemoveFromList(&pCache->pClean, p); pcacheRemoveFromHash(p); pcachePageFree(p); pcacheExitMutex(); }
/* ** 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(void){ PgHdr *p = 0; assert( sqlite3_mutex_held(pcache_g.mutex) ); if( (p=pcache_g.pLruTail)!=0 ){ assert( (p->flags&PGHDR_DIRTY)==0 ); pcacheRemoveFromLruList(p); pcacheRemoveFromHash(p); pcacheRemoveFromList(&p->pCache->pClean, p); } return p; }
/* ** Make every page in the cache clean. */ void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; pcacheEnterMutex(); while( (p = pCache->pDirty)!=0 ){ pcacheRemoveFromList(&pCache->pDirty, p); p->flags &= ~PGHDR_DIRTY; pcacheAddToList(&pCache->pClean, p); if( p->nRef==0 ){ pcacheAddToLruList(p); pCache->nPinned--; } } sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY); expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); pcacheExitMutex(); }