diff --git a/src/main.c b/src/main.c index d7f366b..7717da7 100644 --- a/src/main.c +++ b/src/main.c @@ -167,13 +167,10 @@ char *sqlite3_temp_directory = 0; char *sqlite3_data_directory = 0; /* -** Initialize SQLite. +** 初始化 SQLITE3 入口 ** -** This routine must be called to initialize the memory allocation, -** VFS, and mutex subsystems prior to doing any serious work with -** 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(). +** 由 SQLITE_OMIT_AUTOINIT 宏控制 +** 初始化 内存,VFS,mutex 子系统 ** ** 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. diff --git a/src/pcache.c b/src/pcache.c index 8a96cbe..2a0ff4d 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -39,7 +39,7 @@ ** pointers). */ 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 */ i64 nRefSum; /* Sum of ref counts over all pages */ int szCache; /* Configured cache size */ @@ -47,10 +47,10 @@ struct PCache { int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ 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 */ void *pStress; /* Argument to xStress */ - sqlite3_pcache *pCache; /* Pluggable cache module */ + sqlite3_pcache *pCache; /* 可插拔的 cache 模块实现 */ }; /********************************** Test and Debug Logic **********************/ @@ -403,17 +403,18 @@ sqlite3_pcache_page *sqlite3PcacheFetch( assert( createFlag==3 || createFlag==0 ); assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); - /* eCreate defines what to do if the page does not exist. - ** 0 Do not allocate a new page. (createFlag==0) - ** 1 Allocate a new page if doing so is inexpensive. + /* eCreate 定义页面不存在时的操作 + ** 0 不分配新页面. (createFlag==0) + ** 1 开销较小时,分配新页面. ** (createFlag==1 AND bPurgeable AND pDirty) - ** 2 Allocate a new page even it doing so is difficult. + ** 2 分配新页面. ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); + /* 调用 pcache1.c 中的 pcache1Fetch 函数 */ pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno, createFlag?" create":"",pRes)); diff --git a/src/pcache1.c b/src/pcache1.c index adbe953..0cddeda 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -119,16 +119,16 @@ struct PgHdr1 { unsigned int iKey; /* Key value (page number) */ u16 isBulkLocal; /* This page from bulk local storage */ u16 isAnchor; /* This is the PGroup.lru element */ - PgHdr1 *pNext; /* Next in hash table chain */ - PCache1 *pCache; /* Cache that currently owns this page */ - PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */ - PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ + PgHdr1 *pNext; /* Hash 表中的 next */ + PCache1 *pCache; /* 当前页面所属的 cache */ + PgHdr1 *pLruNext; /* LRU 链表中的 next */ + PgHdr1 *pLruPrev; /* LRU 链表中的 prev */ /* NB: pLruPrev is only valid if pLruNext!=0 */ }; /* -** A page is pinned if it is not on the LRU list. To be "pinned" means -** that the page is in active use and must not be deallocated. +** PINNED 页面在使用中,不会被释放,即不在 LRU 链表中 +** UNPINNED 页面不在使用中,即在 LRU 链表中,如果可能可以被替换掉 */ #define PAGE_IS_PINNED(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 nMinPage; /* Sum of nMin for purgeable caches */ 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 */ }; @@ -180,11 +180,11 @@ struct PCache1 { ** The PGroup mutex must be held when accessing nMax. */ PGroup *pGroup; /* PGroup this cache belongs to */ - unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */ - int szPage; /* Size of database content section */ + unsigned int *pnPurgeable; /* 指向 pGroup->nPurgeable 总可替换页数量 */ + int szPage; /* 页面大小 */ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ - int szAlloc; /* Total size of one pcache line */ - int bPurgeable; /* True if cache is purgeable */ + int szAlloc; /* 总大小,包含页面和元数据 */ + int bPurgeable; /* 页面是否能被重用,即淘汰替换页内容 */ unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ @@ -194,10 +194,10 @@ struct PCache1 { /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. */ - unsigned int nRecyclable; /* Number of pages in the LRU list */ - unsigned int nPage; /* Total number of pages in apHash */ - unsigned int nHash; /* Number of slots in apHash[] */ - PgHdr1 **apHash; /* Hash table for fast lookup by key */ + unsigned int nRecyclable; /* LRU 链表中剩余的节点 */ + unsigned int nPage; /* Hash 表中的节点数量,即所有页数量 */ + unsigned int nHash; /* Hash 表 slot 数量 */ + PgHdr1 **apHash; /* Hash 表用于快速查找 key */ PgHdr1 *pFree; /* List of unused pcache-local pages */ 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 { PGroup grp; /* The global PGroup for mode (2) */ @@ -427,7 +427,7 @@ static int pcache1MemSize(void *p){ #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ /* -** Allocate a new page object initially associated with cache pCache. +** 分配新页面到 cache 中 */ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ PgHdr1 *p = 0; @@ -541,6 +541,7 @@ static void pcache1ResizeHash(PCache1 *p){ assert( sqlite3_mutex_held(p->pGroup->mutex) ); + /* 将 slot 扩大 2 倍 */ nNew = p->nHash*2; if( nNew<256 ){ nNew = 256; @@ -551,6 +552,7 @@ static void pcache1ResizeHash(PCache1 *p){ apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew); if( p->nHash ){ sqlite3EndBenignMalloc(); } pcache1EnterMutex(p->pGroup); + /* 拷贝到新 hash table */ if( apNew ){ for(i=0; inHash; i++){ PgHdr1 *pPage; @@ -880,8 +882,10 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( PGroup *pGroup = pCache->pGroup; 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 ); + /* nPinned: 使用中的页面 */ nPinned = pCache->nPage - pCache->nRecyclable; assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); assert( pCache->n90pct == pCache->nMax*9/10 ); @@ -892,11 +896,11 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( )){ return 0; } - + /* hash 优化,如果 hash 中节点数量比 slot 多,做一次 resize */ if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache); assert( pCache->nHash>0 && pCache->apHash ); - /* Step 4. Try to recycle a page. */ + /* Step 4. page 是否能够重用 */ if( pCache->bPurgeable && !pGroup->lru.pLruPrev->isAnchor && ((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, - ** attempt to allocate a new one. + /* Step 5. 任然没有 page 可用,申请新页 */ if( !pPage ){ 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 -** the value of the createFlag argument. 0 means do not allocate a new -** page. 1 means allocate a new page if space is easily available. 2 -** means to try really hard to allocate a new page. +** 由 createFlag 控制是否在 cache 中分配新页 +** 0 不申请 +** 1 如果分配空间算法比较容易,申请 +** 2 申请 ** ** 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 @@ -994,10 +997,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ** ** 5. Otherwise, allocate and return a new page buffer. ** -** There are two versions of this routine. pcache1FetchWithMutex() is -** the general case. pcache1FetchNoMutex() is a faster implementation for -** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper -** invokes the appropriate routine. +** 由函数 pcache1Fetch 选择调用路径: +** pcache1FetchWithMutex() +** pcache1FetchNoMutex() pGroup->mutex == NULL */ static PgHdr1 *pcache1FetchNoMutex( sqlite3_pcache *p, @@ -1007,14 +1009,14 @@ static PgHdr1 *pcache1FetchNoMutex( PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; - /* Step 1: Search the hash table for an existing entry. */ + /* Step 1: 查找 hash 表,key 是否存在 */ pPage = pCache->apHash[iKey % pCache->nHash]; while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } - /* Step 2: If the page was found in the hash table, then return it. - ** If the page was not in the hash table and createFlag is 0, abort. - ** Otherwise (page not in hash and createFlag!=0) continue with - ** subsequent steps to try to create the page. */ + /* Step 2: 查找到该页,直接返回。] + ** 页面不存在且不能分配,直接 abort + ** 否则分配新页面 + */ if( pPage ){ if( PAGE_IS_UNPINNED(pPage) ){ return pcache1PinPage(pPage);