/* ** 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); } } }
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; }
/* ** 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(); }
/* ** Try to obtain a page from the cache. */ int sqlite3PcacheFetch( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ int createFlag, /* If true, create page if it does not exist already */ PgHdr **ppPage /* Write the page here */ ){ int rc = SQLITE_OK; PgHdr *pPage = 0; assert( pcache_g.isInit ); assert( pCache!=0 ); assert( pgno>0 ); expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); pcacheEnterMutex(); /* 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 ){ if( 0==(pPage->flags&PGHDR_DIRTY) ){ pcacheRemoveFromLruList(pPage); pCache->nPinned++; } pCache->nRef++; } pPage->nRef++; break; } } } if( !pPage && createFlag ){ if( pCache->nHash<=pCache->nPage ){ rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2); } if( rc==SQLITE_OK ){ rc = pcacheRecycleOrAlloc(pCache, &pPage); } if( rc==SQLITE_OK ){ pPage->pPager = 0; pPage->flags = 0; pPage->pDirty = 0; pPage->pgno = pgno; pPage->pCache = pCache; pPage->nRef = 1; pCache->nRef++; pCache->nPinned++; pcacheAddToList(&pCache->pClean, pPage); pcacheAddToHash(pPage); } } pcacheExitMutex(); *ppPage = pPage; expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); assert( pPage || !createFlag || rc!=SQLITE_OK ); return rc; }