pcache lru 注释
parent
6044cf0556
commit
c08c2c1620
|
@ -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
|
** 初始化 内存,VFS,mutex 子系统
|
||||||
** 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.
|
||||||
|
|
15
src/pcache.c
15
src/pcache.c
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue