Sqlite3源码学习(5)OS的接口VFS

    之前讲了那么多的环境搭建,现在终于可以学习源码了。官方有一篇讲解VFS的文档,对理解sqlite3VFS有很大的帮助:

http://www.sqlite.org/vfs.html

1.VFS简介

      VFS也就是所谓的虚拟文件系统,因为sqlite3运行在不同的平台上会有不同的文件系统,VFS就是对不同的文件系统做一个统一的接口。

      先来看一下一张图:

             clip_image001[4]

这张图展示了sqlite3的软件层次结构,主要分为前端和后端,OS层位于最底层,是和系统的磁盘文件存储直接打交道,在OS层里封装了VFS

Sqlit3VFS体现了跨平台的特性,虽然不同文件系统的实现是不一样的,但是接口都是相同的。

2.VFS的组成

VFS最基本的对象是sqlite3_vfs结构体:

typedef struct sqlite3_vfs sqlite3_vfs;
typedef void (*sqlite3_syscall_ptr)(void);
struct sqlite3_vfs {
  int iVersion;            /* Structure version number (currently 3) */
  int szOsFile;            /* Size of subclassed sqlite3_file */
  int mxPathname;          /* Maximum file pathname length */
  sqlite3_vfs *pNext;      /* Next registered VFS */
  const char * zName;       /* Name of this virtual file system */
  void *pAppData;          /* Pointer to application-specific data */
  int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
               int flags, int *pOutFlags);
  int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
  int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
  int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
  void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
  void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
  void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);
  void (*xDlClose)(sqlite3_vfs*, void*);
  int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
  int (*xSleep)(sqlite3_vfs*, int microseconds);
  int (*xCurrentTime)(sqlite3_vfs*, double*);
  int (*xGetLastError)(sqlite3_vfs*, int, char *);
  /*
  ** The methods above are in version 1 of the sqlite_vfs object
  ** definition.  Those that follow are added in version 2 or later
  */
  int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
  /*
  ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
  ** Those below are for version 3 and greater.
  */
  int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
  sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
  const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
  /*
  ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
  ** New fields may be appended in future versions.  The iVersion
  ** value will increment whenever this happens.
  */
};

结构体里定义了一系列函数指针,几个关键的地方是:
int szOsFile: file结构体的大小,继承自sqlite3_file,分配空间时要用
sqlite3_vfs *pNext;:指向下一个vfs节点的指针
const char * zName:vfs的名字
void *pAppData:这个指针指向一个存储了各种文件io操作方法的结构体地址,如win下是

typedef struct winVfsAppData winVfsAppData;
struct winVfsAppData {
  const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */
  void *pAppData;                    /* The extra pAppData, if any. */
  BOOL bNoLock;                      /* Non-zero if locking is disabled. */
};
static winVfsAppData winAppData = {
  &winIoMethod,       /* pMethod */
  0,                  /* pAppData */
  0                   /* bNoLock */
};

要实现一个VFS实体,就是实现sqlite3_vfssqlite3_io_methods结构体里的一系列方法,即函数指针的实体函数的实现,sqlite3_file结构体作为一个文件句柄的传入参数,在open时会将sqlite3_file指针强制转为特定的file指针,该file结构体从sqlite3_file继承,感觉有点像C++sqlite3_file相当于一个基类,在不同VFS下有不同的派生类。

3.VFS的类型

win下的vfswin32win32-longpathwin32-nonewin32-longpath-none,默认使用的是win32 vfs;在类unix系统下的vfsunixunix-dotfilunix-exclunix-none等,默认使用的是unix vfssqlite3内核在初始化时调用sqlite3_os_init()函数来注册vfssqlite3_os_init()在不同系统下有不同的实现。

除了上面这些在test文件里还实现了一些其他的vfs

test_demovfs.c:最简单的vfs,可以学习vfs的基本实现

test_onefile.c:用于嵌入式设备的vfs

test_quota.c:实现了一个名为quotavfs、功能暂时不清楚,具体见官方文档

test_multiplex.c:这个vfs好像是用来处理大文件,具体见官方文档

test_journal.c:这个vfs主要测试回滚日志的存储

test_vfs.c:这个文件主要实现文件系统出错的模拟

4.VFS的注册和使用

如果vfs没有在sqlite3_os_init()里注册,那么就要使用sqlite3_vfs_register函数来注册,其实现如下:

int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
  MUTEX_LOGIC(sqlite3_mutex *mutex;)
#ifndef SQLITE_OMIT_AUTOINIT
  int rc = sqlite3_initialize();
  if( rc ) return rc;
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
  if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
#endif
 
  MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
  sqlite3_mutex_enter(mutex);
  vfsUnlink(pVfs);
  if( makeDflt || vfsList==0 ){
    pVfs->pNext = vfsList;
    vfsList = pVfs;
  }else{
    pVfs->pNext = vfsList->pNext;
    vfsList->pNext = pVfs;
  }
  assert(vfsList);
  sqlite3_mutex_leave(mutex);
  return SQLITE_OK;
}

这个函数的传入参数为要注册的vfs地址pVfsmakeDflt,将pVfsv存储到链表中,vfsList为头节点,如果makeDflt不为0,那么pVfs作为头节点,否则pVfs指向头节点的下一个节点,这里添加节点时需要加锁,防止多线程时被重入。

注册后就可以通过调用sqlite3_open_v2()来替换vfs,下面以demo vfs为示例

    sqlite3_vfs_register(sqlite3_demovfs(), 1);//注册
    int rc = sqlite3_open_v2("demo.db", &db, SQLITE_OPEN_READWRITE, "demo");//使用demo vfs替换默认的vfs
  在tcl下的使用时,先运行上篇讲的tcl扩展程序,输入以下命令
    register_demovfs #注册demo vfs
    sqlite3 db example1.db -vfs demo #打开example1.db数据库,并选择demo vfs替换默认的vfs。
    db eval {CREATE TABLE t1(a TEXT, b INTEGER)} #新建表
db eval {
   INSERT INTO t1 VALUES('one',1);
   INSERT INTO t1 VALUES('two',2); 
   INSERT INTO t1 VALUES(NULL,3);
}  #插入行
    puts [db eval {SELECT * FROM t1}] #显示表的所有行,最后输出结果:
    one 1 two 2 {} 3


  关于sqlite3tcl的使用参考以下文档
http://nut.sourceforge.net/drh.html
http://www.sqlite.org/tclsqlite.html
 
 
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值