设为首页 加入收藏

TOP

SQLite3源码学习之test_vfs的共享内存机制讲解(一)
2018-03-20 08:51:07 】 浏览:204
Tags:SQLite3 源码 习之 test_vfs 共享 内存 机制 讲解

VFS的IO接口里提供了文件的共享缓存机制,在test_vfs里内置了一个Shared memory模块用来模拟测试文件的共享缓存,而不是使用原来的VFS提供的接口。

1.结构定义

pFd结构

每一个数据库文件的连接都对应着一个连接句柄pFile,上层函数调用VFS接口时会传入pFile,在test_vfs里pFile会被强制转换为TestvfsFile*类型,相当于sqlite3_file*的一个继承

typedef struct sqlite3_file sqlite3_file;
struct sqlite3_file {
  const struct sqlite3_io_methods *pMethods;  /* Methods for an open file */
};
sqlite3_file *pFile;// pFile作为连接句柄传入

/*强制转换为TestvfsFile*类型*/
typedef struct TestvfsFd TestvfsFd;
struct TestvfsFile {
  sqlite3_file base;              /* Base class.  Must be first */
  TestvfsFd *pFd;                 /* File data */
};
#define tvfsGetFd(pFile) (((TestvfsFile *)pFile)->pFd)

/*从连接句柄中提取pFd*/
typedef struct TestvfsFd TestvfsFd;
struct TestvfsFd {
  sqlite3_vfs *pVfs;              /* The VFS */
  const char *zFilename;          /* Filename as passed to xOpen() */
  sqlite3_file *pReal;            /* The real, underlying file descriptor */
  Tcl_Obj *pShmId;                /* Shared memory id for Tcl callbacks */

  TestvfsBuffer *pShm;            /* Shared memory buffer */
  u32 excllock;                   /* Mask of exclusive locks */
  u32 sharedlock;                 /* Mask of shared locks */
  TestvfsFd *pNext;               /* Next handle opened on the same file */
};
TestvfsFd *pFd = tvfsGetFd(pFile);//每个连接对应一个pFd

clip_image002

pBuffer结构

pBuffer用来存储共享缓存,每一个文件都有自己的缓存,这些缓存组成一个链表。如果有多个连接打开同一个文件,那么相同文件对应连接的pFd又会组成一个链表,pFile指向pFd的表头。

pBuffer的类型为TestvfsBuffer*,定义如下:

struct TestvfsBuffer {
  char *zFile;                    /* Associated file name */
  int pgsz;                       /* Page size */
  u8 *aPage[TESTVFS_MAX_PAGES];   /* Array of ckalloc'd pages */
  TestvfsFd *pFile;               /* List of open handles */
  TestvfsBuffer *pNext;           /* Next in linked list of all buffers */
};

缓存链表的表头pBuffer存在pFd->pVfs->pAppData里

clip_image004

结构关系

 

假设用多个连接打开同一个文件,其关系如下

clip_image006

 

2.具体实现

tvfsShmMap():

获取共享缓存中的具体页面空间

static int tvfsShmMap(
  sqlite3_file *pFile,            /* Handle open on database file */
  int iPage,                      /* Page to retrieve */
  int pgsz,                       /* Size of pages */
  int isWrite,                    /* True to extend file if necessary */
  void volatile **pp              /* OUT: Mapped memory */
){
  int rc = SQLITE_OK;
  TestvfsFd *pFd = tvfsGetFd(pFile);
  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);

 ……
/*如果该连接的缓存不存在,为该连接分配缓存*/
  if( 0==pFd->pShm ){
    rc = tvfsShmOpen(pFile); 
    if( rc!=SQLITE_OK ){
      return rc;
    }
  }
……
/*如果第iPage页的缓存为空,那么分配pgsz 长度的空间*/
  if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){
    tvfsAllocPage(pFd->pShm, iPage, pgsz);
  }
  *pp = (void volatile *)pFd->pShm->aPage[iPage];

  return rc;
}

tvfsShmOpen():

为对应的连接分配缓存地址,如果缓存不存在,那么新建一个节点插入到pFd链表中。

static int tvfsShmOpen(sqlite3_file *pFile){
  Testvfs *p;
  int rc = SQLITE_OK;             /* Return code */
  TestvfsBuffer *pBuffer;         /* Buffer to open connection to */
  TestvfsFd *pFd;                 /* The testvfs file structure */

  pFd = tvfsGetFd(pFile);
  p = (Testvfs *)pFd->pVfs->pAppData;
  assert( 0==p->isFullshm );
  assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 );
     ……

  /* Search for a TestvfsBuffer. Create a new one if required. */
  for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
    if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;
  }
  /*如果缓存链表中没有该连接文件的缓存,新建一个节点插入到pBuffer链表中*/
  if( !pBuffer ){
    int szName = (int)strlen(pFd->zFilename);
    int nByte = sizeof(TestvfsBuffer) + szName + 1;
    pBuffer = (TestvfsBuffer *)ckalloc(nByte);
    memset(pBuffer, 0,
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇一个GreenDao简单封装数据库新建.. 下一篇7种数据库的详情分析

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目