SQLite3源码学习(9)Page Cache概述

        Page cache是进程分配的内存空间,用来缓存数据页面。page cache的管理独立于操作系统,当一个线程打开一个数据库连接时就会建立一个page cache,对于一个进程中的多线程,它们可以有独立的cache也可以共享一个cahce,下图描述了page cache的结构:

clip_image002

Pager初始化时为pPager->pPCache分配了空间,pPCachePCache类型的结构体,其成员变量定义如下:

struct PCache {
  PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
  PgHdr *pSynced;                     /* Last synced page in dirty page list */
  int nRefSum;                        /* Sum of ref counts over all pages */
  int szCache;                        /* Configured cache size */
  int szSpill;                        /* Size before spilling occurs */
  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() */
  int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
  void *pStress;                      /* Argument to xStress */
  sqlite3_pcache *pCache;             /* Pluggable cache module */
};

page cache的一系列管理操作中,pPCache会作为句柄传入。cache的空间是以一个个slot组织在一起的,这些slot组成一个hash表来存放page。每个在cache里的pagePgHdr结构体来表示:

struct PgHdr {
  sqlite3_pcache_page *pPage;    /* Pcache object page handle */
  void *pData;                   /* Page data */
  void *pExtra;                  /* Extra content */
  PCache *pCache;                /* PRIVATE: Cache that owns this page */
  PgHdr *pDirty;                 /* Transient list of dirty sorted by pgno */
  Pager *pPager;                 /* The pager this page is part of */
  Pgno pgno;                     /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
  u32 pageHash;                  /* Hash of page content */
#endif
  u16 flags;                     /* PGHDR flags defined below */
 
  /**********************************************************************
  ** Elements above, except pCache, are public.  All that follow are
  ** private to pcache.c and should not be accessed by other modules.
  ** pCache is grouped with the public elements for efficiency.
  */
  i16 nRef;                      /* Number of users of this page */
  PgHdr *pDirtyNext;             /* Next element in list of dirty pages */
  PgHdr *pDirtyPrev;             /* Previous element in list of dirty pages */
};

page cache使用的是一种可插入式的cache管理方式,这也就是说page cache先搭建了一个cache的框架,这部分代码在pcache.c里,而对于slot的具体管理如创建hash表, page的添加删除和查找、页面置换算法LRU等操作通过接口来实现,接口定义了一系列相关的函数,sqlite3GlobalConfig.pcache2就是实现这个接口的结构体,其定义如下:

struct sqlite3_pcache_methods2 {
  int iVersion;
  void *pArg;
  int (*xInit)(void*);
  void (*xShutdown)(void*);
  sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);
  void (*xCachesize)(sqlite3_pcache*, int nCachesize);
  int (*xPagecount)(sqlite3_pcache*);
  sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
  void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
  void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
      unsigned oldKey, unsigned newKey);
  void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
  void (*xDestroy)(sqlite3_pcache*);
  void (*xShrink)(sqlite3_pcache*);
};

可以看到sqlite3GlobalConfig.pcache2包含了一系列函数指针,通过diaosqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);来初始化。defaultMethods是一个默认的方法,其函数的实现在PCache 1.c

  static const sqlite3_pcache_methods2 defaultMethods = {
    1,                       /* iVersion */
    0,                       /* pArg */
    pcache1Init,             /* xInit */
    pcache1Shutdown,         /* xShutdown */
    pcache1Create,           /* xCreate */
    pcache1Cachesize,        /* xCachesize */
    pcache1Pagecount,        /* xPagecount */
    pcache1Fetch,            /* xFetch */
    pcache1Unpin,            /* xUnpin */
    pcache1Rekey,            /* xRekey */
    pcache1Truncate,         /* xTruncate */
    pcache1Destroy,          /* xDestroy */
    pcache1Shrink            /* xShrink */
  };

pcache1就相当于page cache的一个插件,在PCache结构体里有如下成员变量sqlite3_pcache *pCachesqlite3_pcache是一个没有具体定义的结构体,在pcache1插件中,PCache1结构体是一个对sqlite3_pcache重新定义的实体,同时PgHdr也会被重新定义成PgHdr1,下图可以大致描述pcache1的轮廓

如果page的数量超过hash表的长度,相同hash值的page会通过链表形成一个桶。pinned page表示正在使用的page,不能被回收,unpinned page表示未使用的page,通过一个双向链表连接在一起,当cache满了后,会通过LRU算法替换掉最久未使用的page

除了pcache1外,test_pcache.c中还实现了一个简单的page cache插件testPcache,该插件可以替换来替换pcache1,调用sqlite3_config(SQLITE_CONFIG_PCACHE2, &testPcache)即可替换

以上图片都取自SQLite Database System Design and Implementation》

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值