pcache lru 注释

main
yezhengmao 2023-06-28 18:35:25 +08:00
parent 6044cf0556
commit c08c2c1620
3 changed files with 50 additions and 50 deletions

View File

@ -167,13 +167,10 @@ char *sqlite3_temp_directory = 0;
char *sqlite3_data_directory = 0; char *sqlite3_data_directory = 0;
/* /*
** Initialize SQLite. ** SQLITE3
** **
** This routine must be called to initialize the memory allocation, ** SQLITE_OMIT_AUTOINIT
** VFS, and mutex subsystems prior to doing any serious work with ** VFSmutex
** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT
** this routine will be called automatically by key routines such as
** sqlite3_open().
** **
** This routine is a no-op except on its very first call for the process, ** This routine is a no-op except on its very first call for the process,
** or for the first call after a call to sqlite3_shutdown. ** or for the first call after a call to sqlite3_shutdown.

View File

@ -39,7 +39,7 @@
** pointers). ** pointers).
*/ */
struct PCache { struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ PgHdr *pDirty, *pDirtyTail; /* LRU 顺序排列的脏页 */
PgHdr *pSynced; /* Last synced page in dirty page list */ PgHdr *pSynced; /* Last synced page in dirty page list */
i64 nRefSum; /* Sum of ref counts over all pages */ i64 nRefSum; /* Sum of ref counts over all pages */
int szCache; /* Configured cache size */ int szCache; /* Configured cache size */
@ -47,10 +47,10 @@ struct PCache {
int szPage; /* Size of every page in this cache */ int szPage; /* Size of every page in this cache */
int szExtra; /* Size of extra space for each page */ int szExtra; /* Size of extra space for each page */
u8 bPurgeable; /* True if pages are on backing store */ u8 bPurgeable; /* True if pages are on backing store */
u8 eCreate; /* eCreate value for for xFetch() */ u8 eCreate; /* xFetch 函数使用,是否创建页面 */
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
void *pStress; /* Argument to xStress */ void *pStress; /* Argument to xStress */
sqlite3_pcache *pCache; /* Pluggable cache module */ sqlite3_pcache *pCache; /* 可插拔的 cache 模块实现 */
}; };
/********************************** Test and Debug Logic **********************/ /********************************** Test and Debug Logic **********************/
@ -403,17 +403,18 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
assert( createFlag==3 || createFlag==0 ); assert( createFlag==3 || createFlag==0 );
assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
/* eCreate defines what to do if the page does not exist. /* eCreate 定义页面不存在时的操作
** 0 Do not allocate a new page. (createFlag==0) ** 0 . (createFlag==0)
** 1 Allocate a new page if doing so is inexpensive. ** 1 .
** (createFlag==1 AND bPurgeable AND pDirty) ** (createFlag==1 AND bPurgeable AND pDirty)
** 2 Allocate a new page even it doing so is difficult. ** 2 .
** (createFlag==1 AND !(bPurgeable AND pDirty) ** (createFlag==1 AND !(bPurgeable AND pDirty)
*/ */
eCreate = createFlag & pCache->eCreate; eCreate = createFlag & pCache->eCreate;
assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( eCreate==0 || eCreate==1 || eCreate==2 );
assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
/* 调用 pcache1.c 中的 pcache1Fetch 函数 */
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno, pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
createFlag?" create":"",pRes)); createFlag?" create":"",pRes));

View File

@ -119,16 +119,16 @@ struct PgHdr1 {
unsigned int iKey; /* Key value (page number) */ unsigned int iKey; /* Key value (page number) */
u16 isBulkLocal; /* This page from bulk local storage */ u16 isBulkLocal; /* This page from bulk local storage */
u16 isAnchor; /* This is the PGroup.lru element */ u16 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */ PgHdr1 *pNext; /* Hash 表中的 next */
PCache1 *pCache; /* Cache that currently owns this page */ PCache1 *pCache; /* 当前页面所属的 cache */
PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */ PgHdr1 *pLruNext; /* LRU 链表中的 next */
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ PgHdr1 *pLruPrev; /* LRU 链表中的 prev */
/* NB: pLruPrev is only valid if pLruNext!=0 */ /* NB: pLruPrev is only valid if pLruNext!=0 */
}; };
/* /*
** A page is pinned if it is not on the LRU list. To be "pinned" means ** PINNED 使 LRU
** that the page is in active use and must not be deallocated. ** UNPINNED 使 LRU
*/ */
#define PAGE_IS_PINNED(p) ((p)->pLruNext==0) #define PAGE_IS_PINNED(p) ((p)->pLruNext==0)
#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) #define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0)
@ -160,7 +160,7 @@ struct PGroup {
unsigned int nMaxPage; /* Sum of nMax for purgeable caches */ unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
unsigned int nMinPage; /* Sum of nMin for purgeable caches */ unsigned int nMinPage; /* Sum of nMin for purgeable caches */
unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
unsigned int nPurgeable; /* Number of purgeable pages allocated */ unsigned int nPurgeable; /* 可替换页的数量 */
PgHdr1 lru; /* The beginning and end of the LRU list */ PgHdr1 lru; /* The beginning and end of the LRU list */
}; };
@ -180,11 +180,11 @@ struct PCache1 {
** The PGroup mutex must be held when accessing nMax. ** The PGroup mutex must be held when accessing nMax.
*/ */
PGroup *pGroup; /* PGroup this cache belongs to */ PGroup *pGroup; /* PGroup this cache belongs to */
unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */ unsigned int *pnPurgeable; /* 指向 pGroup->nPurgeable 总可替换页数量 */
int szPage; /* Size of database content section */ int szPage; /* 页面大小 */
int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
int szAlloc; /* Total size of one pcache line */ int szAlloc; /* 总大小,包含页面和元数据 */
int bPurgeable; /* True if cache is purgeable */ int bPurgeable; /* 页面是否能被重用,即淘汰替换页内容 */
unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMin; /* Minimum number of pages reserved */
unsigned int nMax; /* Configured "cache_size" value */ unsigned int nMax; /* Configured "cache_size" value */
unsigned int n90pct; /* nMax*9/10 */ unsigned int n90pct; /* nMax*9/10 */
@ -194,10 +194,10 @@ struct PCache1 {
/* Hash table of all pages. The following variables may only be accessed /* Hash table of all pages. The following variables may only be accessed
** when the accessor is holding the PGroup mutex. ** when the accessor is holding the PGroup mutex.
*/ */
unsigned int nRecyclable; /* Number of pages in the LRU list */ unsigned int nRecyclable; /* LRU 链表中剩余的节点 */
unsigned int nPage; /* Total number of pages in apHash */ unsigned int nPage; /* Hash 表中的节点数量,即所有页数量 */
unsigned int nHash; /* Number of slots in apHash[] */ unsigned int nHash; /* Hash 表 slot 数量 */
PgHdr1 **apHash; /* Hash table for fast lookup by key */ PgHdr1 **apHash; /* Hash 表用于快速查找 key */
PgHdr1 *pFree; /* List of unused pcache-local pages */ PgHdr1 *pFree; /* List of unused pcache-local pages */
void *pBulk; /* Bulk memory used by pcache-local */ void *pBulk; /* Bulk memory used by pcache-local */
}; };
@ -211,7 +211,7 @@ struct PgFreeslot {
}; };
/* /*
** Global data used by this cache. ** cache 使 - pcache1
*/ */
static SQLITE_WSD struct PCacheGlobal { static SQLITE_WSD struct PCacheGlobal {
PGroup grp; /* The global PGroup for mode (2) */ PGroup grp; /* The global PGroup for mode (2) */
@ -427,7 +427,7 @@ static int pcache1MemSize(void *p){
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
/* /*
** Allocate a new page object initially associated with cache pCache. ** cache
*/ */
static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
PgHdr1 *p = 0; PgHdr1 *p = 0;
@ -541,6 +541,7 @@ static void pcache1ResizeHash(PCache1 *p){
assert( sqlite3_mutex_held(p->pGroup->mutex) ); assert( sqlite3_mutex_held(p->pGroup->mutex) );
/* 将 slot 扩大 2 倍 */
nNew = p->nHash*2; nNew = p->nHash*2;
if( nNew<256 ){ if( nNew<256 ){
nNew = 256; nNew = 256;
@ -551,6 +552,7 @@ static void pcache1ResizeHash(PCache1 *p){
apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew); apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew);
if( p->nHash ){ sqlite3EndBenignMalloc(); } if( p->nHash ){ sqlite3EndBenignMalloc(); }
pcache1EnterMutex(p->pGroup); pcache1EnterMutex(p->pGroup);
/* 拷贝到新 hash table */
if( apNew ){ if( apNew ){
for(i=0; i<p->nHash; i++){ for(i=0; i<p->nHash; i++){
PgHdr1 *pPage; PgHdr1 *pPage;
@ -880,8 +882,10 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
PGroup *pGroup = pCache->pGroup; PGroup *pGroup = pCache->pGroup;
PgHdr1 *pPage = 0; PgHdr1 *pPage = 0;
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */ /* Step 3: cache 已经快满了,但是任然请求分配新页,直接 abort */
/* 控制内存申请 */
assert( pCache->nPage >= pCache->nRecyclable ); assert( pCache->nPage >= pCache->nRecyclable );
/* nPinned: 使用中的页面 */
nPinned = pCache->nPage - pCache->nRecyclable; nPinned = pCache->nPage - pCache->nRecyclable;
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
assert( pCache->n90pct == pCache->nMax*9/10 ); assert( pCache->n90pct == pCache->nMax*9/10 );
@ -892,11 +896,11 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
)){ )){
return 0; return 0;
} }
/* hash 优化,如果 hash 中节点数量比 slot 多,做一次 resize */
if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache); if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
assert( pCache->nHash>0 && pCache->apHash ); assert( pCache->nHash>0 && pCache->apHash );
/* Step 4. Try to recycle a page. */ /* Step 4. page 是否能够重用 */
if( pCache->bPurgeable if( pCache->bPurgeable
&& !pGroup->lru.pLruPrev->isAnchor && !pGroup->lru.pLruPrev->isAnchor
&& ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache)) && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache))
@ -915,8 +919,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
} }
} }
/* Step 5. If a usable page buffer has still not been found, /* Step 5. 任然没有 page 可用,申请新页
** attempt to allocate a new one.
*/ */
if( !pPage ){ if( !pPage ){
pPage = pcache1AllocPage(pCache, createFlag==1); pPage = pcache1AllocPage(pCache, createFlag==1);
@ -941,14 +944,14 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
} }
/* /*
** Implementation of the sqlite3_pcache.xFetch method. ** sqlite3_pcache.xFetch .
** **
** Fetch a page by key value. ** key .
** **
** Whether or not a new page may be allocated by this function depends on ** createFlag cache
** the value of the createFlag argument. 0 means do not allocate a new ** 0
** page. 1 means allocate a new page if space is easily available. 2 ** 1
** means to try really hard to allocate a new page. ** 2
** **
** For a non-purgeable cache (a cache used as the storage for an in-memory ** For a non-purgeable cache (a cache used as the storage for an in-memory
** database) there is really no difference between createFlag 1 and 2. So ** database) there is really no difference between createFlag 1 and 2. So
@ -994,10 +997,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** **
** 5. Otherwise, allocate and return a new page buffer. ** 5. Otherwise, allocate and return a new page buffer.
** **
** There are two versions of this routine. pcache1FetchWithMutex() is ** pcache1Fetch
** the general case. pcache1FetchNoMutex() is a faster implementation for ** pcache1FetchWithMutex()
** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper ** pcache1FetchNoMutex() pGroup->mutex == NULL
** invokes the appropriate routine.
*/ */
static PgHdr1 *pcache1FetchNoMutex( static PgHdr1 *pcache1FetchNoMutex(
sqlite3_pcache *p, sqlite3_pcache *p,
@ -1007,14 +1009,14 @@ static PgHdr1 *pcache1FetchNoMutex(
PCache1 *pCache = (PCache1 *)p; PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0; PgHdr1 *pPage = 0;
/* Step 1: Search the hash table for an existing entry. */ /* Step 1: 查找 hash 表key 是否存在 */
pPage = pCache->apHash[iKey % pCache->nHash]; pPage = pCache->apHash[iKey % pCache->nHash];
while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
/* Step 2: If the page was found in the hash table, then return it. /* Step 2: 查找到该页,直接返回。]
** If the page was not in the hash table and createFlag is 0, abort. ** abort
** Otherwise (page not in hash and createFlag!=0) continue with **
** subsequent steps to try to create the page. */ */
if( pPage ){ if( pPage ){
if( PAGE_IS_UNPINNED(pPage) ){ if( PAGE_IS_UNPINNED(pPage) ){
return pcache1PinPage(pPage); return pcache1PinPage(pPage);