/* ** If there are currently more than pcache.nMaxPage pages allocated, try ** to recycle pages to reduce the number allocated to pcache.nMaxPage. */ static void pcacheEnforceMaxPage() { PgHdr *p; assert( sqlite3_mutex_held(pcache.mutex) ); while( pcache.nCurrentPage>pcache.nMaxPage && (p = pcacheRecyclePage()) ) { pcachePageFree(p); } }
/* ** Obtain space for a page. Try to recycle an old page if the limit on the ** number of pages has been reached. If the limit has not been reached or ** there are no pages eligible for recycling, allocate a new page. ** ** Return a pointer to the new page, or NULL if an OOM condition occurs. */ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage) { PgHdr *p = 0; int szPage = pCache->szPage; int szExtra = pCache->szExtra; assert( pcache.isInit ); assert( sqlite3_mutex_held(pcache.mutex) ); *ppPage = 0; /* 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. */ expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); expensive_assert( pcacheCheckSynced(pCache) ); if( pCache->xStress && pCache->pDirty && pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage) ) { 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 ) { int rc; pcacheExitMutex(); rc = pCache->xStress(pCache->pStress, pPg); pcacheEnterMutex(); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ) { return rc; } } } /* If the global page limit has been reached, try to recycle a page. */ if( pCache->bPurgeable && 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->szPage!=szExtra) ) { pcachePageFree(p); p = 0; } if( !p ) { p = pcachePageAlloc(pCache); } *ppPage = p; return (p?SQLITE_OK:SQLITE_NOMEM); }
/* ** This function is called to free superfluous dynamically allocated memory ** held by the pager system. Memory in use by any SQLite pager allocated ** by the current thread may be sqlite3_free()ed. ** ** nReq is the number of bytes of memory required. Once this much has ** been released, the function returns. The return value is the total number ** of bytes of memory released. */ int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; if( pcache_g.pStart==0 ){ PgHdr *p; pcacheEnterMutex(); while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){ nFree += pcachePageSize(p); pcachePageFree(p); } pcacheExitMutex(); } return nFree; }