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

来源:互联网 发布:农村淘宝前景 编辑:程序博客网 时间:2024/05/21 06:19

    之前讲了那么多的环境搭建,现在终于可以学习源码了。官方有一篇讲解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
 
 
原创粉丝点击