📄 pcache.c
字号:
pcacheAddToList(&pCache->pClean, p); if( p->nRef==0 ){ pcacheAddToLruList(p); pCache->nPinned--; } } sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY); expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); pcacheExitMutex();}/*** Change the page number of page p to newPgno. If newPgno is 0, then the** page object is added to the clean-list and the PGHDR_REUSE_UNLIKELY ** flag set.*/void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ assert( p->nRef>0 ); pcacheEnterMutex(); pcacheRemoveFromHash(p); p->pgno = newPgno; if( newPgno==0 ){ p->flags |= PGHDR_REUSE_UNLIKELY; pcacheFree(p->apSave[0]); pcacheFree(p->apSave[1]); p->apSave[0] = 0; p->apSave[1] = 0; if( (p->flags & PGHDR_DIRTY) ){ pcacheMakeClean(p); } } pcacheAddToHash(p); pcacheExitMutex();}/*** Remove all content from a page cache*/void pcacheClear(PCache *pCache){ PgHdr *p, *pNext; assert( sqlite3_mutex_held(pcache.mutex) ); for(p=pCache->pClean; p; p=pNext){ pNext = p->pNext; pcacheRemoveFromLruList(p); pcachePageFree(p); } for(p=pCache->pDirty; p; p=pNext){ pNext = p->pNext; 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]));}/*** 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();}/*** 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); }}/*** Close a cache.*/void sqlite3PcacheClose(PCache *pCache){ pcacheEnterMutex(); /* Free all the pages used by this pager and remove them from the LRU list. */ pcacheClear(pCache); if( pCache->bPurgeable ){ pcache.nMaxPage -= pCache->nMax; pcache.nMinPage -= pCache->nMin; pcacheEnforceMaxPage(); } sqlite3_free(pCache->apHash); pcacheExitMutex();}/*** Preserve the content of the page. It is assumed that the content** has not been preserved already.**** If idJournal==0 then this is for the overall transaction.** If idJournal==1 then this is for the statement journal.**** This routine is used for in-memory databases only.**** Return SQLITE_OK or SQLITE_NOMEM if a memory allocation fails.*/int sqlite3PcachePreserve(PgHdr *p, int idJournal){ void *x; int sz; assert( p->pCache->bPurgeable==0 ); assert( p->apSave[idJournal]==0 ); sz = p->pCache->szPage; p->apSave[idJournal] = x = sqlite3PageMalloc( sz ); if( x==0 ) return SQLITE_NOMEM; memcpy(x, p->pData, sz); return SQLITE_OK;}/*** Commit a change previously preserved.*/void sqlite3PcacheCommit(PCache *pCache, int idJournal){ PgHdr *p; pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */ for(p=pCache->pDirty; p; p=p->pNext){ if( p->apSave[idJournal] ){ pcacheFree(p->apSave[idJournal]); p->apSave[idJournal] = 0; } } pcacheExitMutex();}/*** Rollback a change previously preserved.*/void sqlite3PcacheRollback(PCache *pCache, int idJournal){ PgHdr *p; int sz; pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */ sz = pCache->szPage; for(p=pCache->pDirty; p; p=p->pNext){ if( p->apSave[idJournal] ){ memcpy(p->pData, p->apSave[idJournal], sz); pcacheFree(p->apSave[idJournal]); p->apSave[idJournal] = 0; } } pcacheExitMutex();}/* ** Assert flags settings on all pages. Debugging only.*/void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){ PgHdr *p; for(p=pCache->pDirty; p; p=p->pNext){ assert( (p->flags&trueMask)==trueMask ); assert( (p->flags&falseMask)==0 ); } for(p=pCache->pClean; p; p=p->pNext){ assert( (p->flags&trueMask)==trueMask ); assert( (p->flags&falseMask)==0 ); }}/* ** Discard the contents of the cache.*/int sqlite3PcacheClear(PCache *pCache){ assert(pCache->nRef==0); pcacheEnterMutex(); pcacheClear(pCache); pcacheExitMutex(); return SQLITE_OK;}/*** Merge two lists of pages connected by pDirty and in pgno order.** Do not both fixing the pPrevDirty pointers.*/static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ PgHdr result, *pTail; pTail = &result; while( pA && pB ){ if( pA->pgno<pB->pgno ){ pTail->pDirty = pA; pTail = pA; pA = pA->pDirty; }else{ pTail->pDirty = pB; pTail = pB; pB = pB->pDirty; } } if( pA ){ pTail->pDirty = pA; }else if( pB ){ pTail->pDirty = pB; }else{ pTail->pDirty = 0; } return result.pDirty;}/*** Sort the list of pages in accending order by pgno. Pages are** connected by pDirty pointers. The pPrevDirty pointers are** corrupted by this sort.*/#define N_SORT_BUCKET_ALLOC 25#define N_SORT_BUCKET 25#ifdef SQLITE_TEST int sqlite3_pager_n_sort_bucket = 0; #undef N_SORT_BUCKET #define N_SORT_BUCKET \ (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)#endifstatic PgHdr *pcacheSortDirtyList(PgHdr *pIn){ PgHdr *a[N_SORT_BUCKET_ALLOC], *p; int i; memset(a, 0, sizeof(a)); while( pIn ){ p = pIn; pIn = p->pDirty; p->pDirty = 0; for(i=0; i<N_SORT_BUCKET-1; i++){ if( a[i]==0 ){ a[i] = p; break; }else{ p = pcacheMergeDirtyList(a[i], p); a[i] = 0; } } if( i==N_SORT_BUCKET-1 ){ /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET) ** elements in the input list. This is possible, but impractical. ** Testing this line is the point of global variable ** sqlite3_pager_n_sort_bucket. */ a[i] = pcacheMergeDirtyList(a[i], p); } } p = a[0]; for(i=1; i<N_SORT_BUCKET; i++){ p = pcacheMergeDirtyList(p, a[i]); } return p;}/*** Return a list of all dirty pages in the cache, sorted by page number.*/PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ PgHdr *p; for(p=pCache->pDirty; p; p=p->pNext){ p->pDirty = p->pNext; } return pcacheSortDirtyList(pCache->pDirty);}/* ** Return the total number of outstanding page references.*/int sqlite3PcacheRefCount(PCache *pCache){ return pCache->nRef;}/* ** Return the total number of pages in the cache.*/int sqlite3PcachePagecount(PCache *pCache){ assert( pCache->nPage>=0 ); return pCache->nPage;}#ifdef SQLITE_CHECK_PAGES/*** This function is used by the pager.c module to iterate through all ** pages in the cache. At present, this is only required if the** SQLITE_CHECK_PAGES macro (used for debugging) is specified.*/void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){ PgHdr *p; for(p=pCache->pClean; p; p=p->pNext){ xIter(p); } for(p=pCache->pDirty; p; p=p->pNext){ xIter(p); }}#endif/* ** Set flags on all pages in the page cache */void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){ PgHdr *p; assert( (orMask&PGHDR_NEED_SYNC)==0 ); /* Obtain the global mutex before modifying any PgHdr.flags variables ** or traversing the LRU list. */ pcacheEnterMutex(); for(p=pCache->pDirty; p; p=p->pNext){ p->flags = (p->flags&andMask)|orMask; } for(p=pCache->pClean; p; p=p->pNext){ p->flags = (p->flags&andMask)|orMask; } if( 0==(andMask&PGHDR_NEED_SYNC) ){ pCache->pSynced = pCache->pDirtyTail; assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 ); } pcacheExitMutex();}/*** Set the suggested cache-size value.*/int sqlite3PcacheGetCachesize(PCache *pCache){ return pCache->nMax;}/*** Set the suggested cache-size value.*/void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ if( mxPage<10 ){ mxPage = 10; } if( pCache->bPurgeable ){ pcacheEnterMutex(); pcache.nMaxPage -= pCache->nMax; pcache.nMaxPage += mxPage; pcacheEnforceMaxPage(); pcacheExitMutex(); } pCache->nMax = mxPage;}#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT/*** 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.pStart==0 ){ PgHdr *p; pcacheEnterMutex(); while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){ nFree += pcachePageSize(p); pcachePageFree(p); } pcacheExitMutex(); } return nFree;}#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */#ifdef SQLITE_TESTvoid sqlite3PcacheStats( int *pnCurrent, int *pnMax, int *pnMin, int *pnRecyclable){ PgHdr *p; int nRecyclable = 0; for(p=pcache.pLruHead; p; p=p->pNextLru){ nRecyclable++; } *pnCurrent = pcache.nCurrentPage; *pnMax = pcache.nMaxPage; *pnMin = pcache.nMinPage; *pnRecyclable = nRecyclable;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -