SQLite3源码学习(10)testpcache分析

      testpcachepage cache的一个简单插件,用tcl调试时输入命令sqlite3_shutdownsqlite3_config_alt_pcache 1就会把pcache1替换成testpcache

testpcache由下列函数构成:

  

static const sqlite3_pcache_methods2 testPcache = {
    1,
    (void*)&testpcacheGlobal,
    testpcacheInit,
    testpcacheShutdown,
    testpcacheCreate,
    testpcacheCachesize,
    testpcachePagecount,
    testpcacheFetch,
    testpcacheUnpin,
    testpcacheRekey,
    testpcacheTruncate,
    testpcacheDestroy,
  };

testpcacheInit():

这个函数就是测试系统分配内存是否正常

testpcacheShutdown():

释放testpcacheInit()中给testpcacheGlobal.pDummy分配的内存。

testpcacheRandom():

获得一个伪随机数,种子是sqlite3_config_alt_pcache命令的第4个个输入参数。

testpcacheCreate():

sqlite3_pcache *pCache分配空间,即返回指针testpcache *p。先给p申请内存,内存包括testpcache大小和所有cache page所需的内存:

 nMem =sizeof(testpcache) + TESTPCACHE_NPAGE*(szPage+szExtra);

p = sqlite3_malloc( nMem );

 testpcacheCachesize():

  设置cache中最大的页面数量,目前该函数为空。

  testpcachePagecount():

  获取已经使用的页面数量。

  

 testpcacheFetch():

 取出一个页面,在cache中寻找该页面,如果存在,那么标记该页面为已使用p->a[i].isPinned = 1;

  

/* See if the page is already in cache.  Return immediately if it is */
  for(i=0; i<TESTPCACHE_NPAGE; i++){
    if( p->a[i].key==key ){
      if( !p->a[i].isPinned ){
        p->nPinned++;
        assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
        p->a[i].isPinned = 1;
      }
      return &p->a[i].page;
    }
  }

 如果没有该页面,那么从缓存中取出一个空闲的页面,记录该页面的序号即key值,并标记为已使用

  

/* Find a free page to allocate if there are any free pages.
  ** Withhold TESTPCACHE_RESERVE free pages until createFlag is 2.
  */
  if( p->nFree>TESTPCACHE_RESERVE || (createFlag==2 && p->nFree>0) ){
    j = testpcacheRandom(p) % TESTPCACHE_NPAGE;
    for(i=0; i<TESTPCACHE_NPAGE; i++, j = (j+1)%TESTPCACHE_NPAGE){
      if( p->a[j].key==0 ){
        p->a[j].key = key;
        p->a[j].isPinned = 1;
        memset(p->a[j].page.pBuf, 0, p->szPage);
        memset(p->a[j].page.pExtra, 0, p->szExtra);
        p->nPinned++;
        p->nFree--;
        assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
        return &p->a[j].page;
      }
}

如果没有空闲页面,那么从没有使用的页面中回收一个页面再分配

  /* If there are no free pages, recycle a page.  The page to
  ** recycle is selected at random from all unpinned pages.
  */
  j = testpcacheRandom(p) % TESTPCACHE_NPAGE;
  for(i=0; i<TESTPCACHE_NPAGE; i++, j = (j+1)%TESTPCACHE_NPAGE){
    if( p->a[j].key>0 && p->a[j].isPinned==0 ){
      p->a[j].key = key;
      p->a[j].isPinned = 1;
      memset(p->a[j].page.pBuf, 0, p->szPage);
      memset(p->a[j].page.pExtra, 0, p->szExtra);
      p->nPinned++;
      assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
      return &p->a[j].page;
    }
  }

testpcacheUnpin():

把传进来的pOldPage标记为未使用,并根据discard标志位决定是否释放该页面

for(i=0; i<TESTPCACHE_NPAGE; i++){
    if( &p->a[i].page==pOldPage ){
      /* The pOldPage pointer always points to a pinned page */
      assert( p->a[i].isPinned );
      p->a[i].isPinned = 0;
      p->nPinned--;
      assert( p->nPinned>=0 );
      if( discard ){
        p->a[i].key = 0;
        p->nFree++;
        assert( p->nFree<=TESTPCACHE_NPAGE );
      }
      return;
    }
  }

testpcacheRekey():

重新标记缓存页面的序号,传入两个参数oldKeynewKey,把oldKey的页面序号替换成newKey的值:

  /* Find the page to be rekeyed and rekey it.
  */
  for(i=0; i<TESTPCACHE_NPAGE; i++){
    if( p->a[i].key==oldKey ){
      /* The oldKey and pOldPage parameters match */
      assert( &p->a[i].page==pOldPage );
      /* Page to be rekeyed must be pinned */
      assert( p->a[i].isPinned );
      p->a[i].key = newKey;
      return;
    }
  }

在替换之前如果cache中已经存在页面序号为newKey的页面,那么释放该页面。

testpcacheTruncate():

释放key值大于iLimit的缓存页面:

 for(i=0; i<TESTPCACHE_NPAGE; i++){
    if( p->a[i].key>=iLimit ){
      p->a[i].key = 0;
      if( p->a[i].isPinned ){
        p->nPinned--;
        assert( p->nPinned>=0 );
      }
      p->nFree++;
      assert( p->nFree<=TESTPCACHE_NPAGE );
    }
  }

testpcacheDestroy():销毁pCache

testpcache只是实现了page cache插件最简单的功能,效率更高更完整的实现是pcache1插件,通过对testpcache的学习可以很快知道page cache分配的基本原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值