📄 pcache1.c
字号:
}/******************************************************************************//******** sqlite3_pcache Methods **********************************************//*** Implementation of the sqlite3_pcache.xInit method.*/static int pcache1Init(void *NotUsed){ UNUSED_PARAMETER(NotUsed); memset(&pcache1, 0, sizeof(pcache1)); if( sqlite3GlobalConfig.bCoreMutex ){ pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); } return SQLITE_OK;}/*** Implementation of the sqlite3_pcache.xShutdown method.*/static void pcache1Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); /* no-op */}/*** Implementation of the sqlite3_pcache.xCreate method.**** Allocate a new cache.*/static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){ PCache1 *pCache; pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1)); if( pCache ){ memset(pCache, 0, sizeof(PCache1)); pCache->szPage = szPage; pCache->bPurgeable = (bPurgeable ? 1 : 0); if( bPurgeable ){ pCache->nMin = 10; pcache1EnterMutex(); pcache1.nMinPage += pCache->nMin; pcache1LeaveMutex(); } } return (sqlite3_pcache *)pCache;}/*** Implementation of the sqlite3_pcache.xCachesize method. **** Configure the cache_size limit for a cache.*/static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ PCache1 *pCache = (PCache1 *)p; if( pCache->bPurgeable ){ pcache1EnterMutex(); pcache1.nMaxPage += (nMax - pCache->nMax); pCache->nMax = nMax; pcache1EnforceMaxPage(); pcache1LeaveMutex(); }}/*** Implementation of the sqlite3_pcache.xPagecount method. */static int pcache1Pagecount(sqlite3_pcache *p){ int n; pcache1EnterMutex(); n = ((PCache1 *)p)->nPage; pcache1LeaveMutex(); return n;}/*** Implementation of the sqlite3_pcache.xFetch method. **** Fetch a page by key value.**** Whether or not a new page may be allocated by this function depends on** the value of the createFlag argument.**** There are three different approaches to obtaining space for a page,** depending on the value of parameter createFlag (which may be 0, 1 or 2).**** 1. Regardless of the value of createFlag, the cache is searched for a ** copy of the requested page. If one is found, it is returned.**** 2. If createFlag==0 and the page is not already in the cache, NULL is** returned.**** 3. If createFlag is 1, the cache is marked as purgeable and the page is ** not already in the cache, and if either of the following are true, ** return NULL:**** (a) the number of pages pinned by the cache is greater than** PCache1.nMax, or** (b) the number of pages pinned by the cache is greater than** the sum of nMax for all purgeable caches, less the sum of ** nMin for all other purgeable caches. **** 4. If none of the first three conditions apply and the cache is marked** as purgeable, and if one of the following is true:**** (a) The number of pages allocated for the cache is already ** PCache1.nMax, or**** (b) The number of pages allocated for all purgeable caches is** already equal to or greater than the sum of nMax for all** purgeable caches,**** then attempt to recycle a page from the LRU list. If it is the right** size, return the recycled buffer. Otherwise, free the buffer and** proceed to step 5. **** 5. Otherwise, allocate and return a new page buffer.*/static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){ unsigned int nPinned; PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; pcache1EnterMutex(); if( createFlag==1 ) sqlite3BeginBenignMalloc(); /* Search the hash table for an existing entry. */ if( pCache->nHash>0 ){ unsigned int h = iKey % pCache->nHash; for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext); } if( pPage || createFlag==0 ){ pcache1PinPage(pPage); goto fetch_out; } /* Step 3 of header comment. */ nPinned = pCache->nPage - pCache->nRecyclable; if( createFlag==1 && pCache->bPurgeable && ( nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage) || nPinned>=(pCache->nMax) )){ goto fetch_out; } if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){ goto fetch_out; } /* Step 4. Try to recycle a page buffer if appropriate. */ if( pCache->bPurgeable && pcache1.pLruTail && ( pCache->nPage>=pCache->nMax-1 || pcache1.nCurrentPage>=pcache1.nMaxPage )){ pPage = pcache1.pLruTail; pcache1RemoveFromHash(pPage); pcache1PinPage(pPage); if( pPage->pCache->szPage!=pCache->szPage ){ pcache1FreePage(pPage); pPage = 0; }else{ pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable); } } /* Step 5. If a usable page buffer has still not been found, ** attempt to allocate a new one. */ if( !pPage ){ pPage = pcache1AllocPage(pCache); } if( pPage ){ unsigned int h = iKey % pCache->nHash; *(void **)(PGHDR1_TO_PAGE(pPage)) = 0; pCache->nPage++; pPage->iKey = iKey; pPage->pNext = pCache->apHash[h]; pPage->pCache = pCache; pPage->pLruPrev = 0; pPage->pLruNext = 0; pCache->apHash[h] = pPage; }fetch_out: if( pPage && iKey>pCache->iMaxKey ){ pCache->iMaxKey = iKey; } if( createFlag==1 ) sqlite3EndBenignMalloc(); pcache1LeaveMutex(); return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);}/*** Implementation of the sqlite3_pcache.xUnpin method.**** Mark a page as unpinned (eligible for asynchronous recycling).*/static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg); pcache1EnterMutex(); /* It is an error to call this function if the page is already ** part of the global LRU list. */ assert( pPage->pLruPrev==0 && pPage->pLruNext==0 ); assert( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage ); if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){ pcache1RemoveFromHash(pPage); pcache1FreePage(pPage); }else{ /* Add the page to the global LRU list. Normally, the page is added to ** the head of the list (last page to be recycled). However, if the ** reuseUnlikely flag passed to this function is true, the page is added ** to the tail of the list (first page to be recycled). */ if( pcache1.pLruHead ){ pcache1.pLruHead->pLruPrev = pPage; pPage->pLruNext = pcache1.pLruHead; pcache1.pLruHead = pPage; }else{ pcache1.pLruTail = pPage; pcache1.pLruHead = pPage; } pCache->nRecyclable++; } pcache1LeaveMutex();}/*** Implementation of the sqlite3_pcache.xRekey method. */static void pcache1Rekey( sqlite3_pcache *p, void *pPg, unsigned int iOld, unsigned int iNew){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg); PgHdr1 **pp; unsigned int h; assert( pPage->iKey==iOld ); pcache1EnterMutex(); h = iOld%pCache->nHash; pp = &pCache->apHash[h]; while( (*pp)!=pPage ){ pp = &(*pp)->pNext; } *pp = pPage->pNext; h = iNew%pCache->nHash; pPage->iKey = iNew; pPage->pNext = pCache->apHash[h]; pCache->apHash[h] = pPage; if( iNew>pCache->iMaxKey ){ pCache->iMaxKey = iNew; } pcache1LeaveMutex();}/*** Implementation of the sqlite3_pcache.xTruncate method. **** Discard all unpinned pages in the cache with a page number equal to** or greater than parameter iLimit. Any pinned pages with a page number** equal to or greater than iLimit are implicitly unpinned.*/static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){ PCache1 *pCache = (PCache1 *)p; pcache1EnterMutex(); if( iLimit<=pCache->iMaxKey ){ pcache1TruncateUnsafe(pCache, iLimit); pCache->iMaxKey = iLimit-1; } pcache1LeaveMutex();}/*** Implementation of the sqlite3_pcache.xDestroy method. **** Destroy a cache allocated using pcache1Create().*/static void pcache1Destroy(sqlite3_pcache *p){ PCache1 *pCache = (PCache1 *)p; pcache1EnterMutex(); pcache1TruncateUnsafe(pCache, 0); pcache1.nMaxPage -= pCache->nMax; pcache1.nMinPage -= pCache->nMin; pcache1EnforceMaxPage(); pcache1LeaveMutex(); sqlite3_free(pCache->apHash); sqlite3_free(pCache);}/*** This function is called during initialization (sqlite3_initialize()) to** install the default pluggable cache module, assuming the user has not** already provided an alternative.*/void sqlite3PCacheSetDefault(void){ static sqlite3_pcache_methods defaultMethods = { 0, /* pArg */ pcache1Init, /* xInit */ pcache1Shutdown, /* xShutdown */ pcache1Create, /* xCreate */ pcache1Cachesize, /* xCachesize */ pcache1Pagecount, /* xPagecount */ pcache1Fetch, /* xFetch */ pcache1Unpin, /* xUnpin */ pcache1Rekey, /* xRekey */ pcache1Truncate, /* xTruncate */ pcache1Destroy /* xDestroy */ }; sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);}#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( pcache1.pStart==0 ){ PgHdr1 *p; pcache1EnterMutex(); while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){ nFree += sqlite3MallocSize(p); pcache1PinPage(p); pcache1RemoveFromHash(p); pcache1FreePage(p); } pcache1LeaveMutex(); } return nFree;}#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */#ifdef SQLITE_TEST/*** This function is used by test procedures to inspect the internal state** of the global cache.*/void sqlite3PcacheStats( int *pnCurrent, /* OUT: Total number of pages cached */ int *pnMax, /* OUT: Global maximum cache size */ int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */ int *pnRecyclable /* OUT: Total number of pages available for recycling */){ PgHdr1 *p; int nRecyclable = 0; for(p=pcache1.pLruHead; p; p=p->pLruNext){ nRecyclable++; } *pnCurrent = pcache1.nCurrentPage; *pnMax = pcache1.nMaxPage; *pnMin = pcache1.nMinPage; *pnRecyclable = nRecyclable;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -