美文网首页
SQLite架构

SQLite架构

作者: NJUShenbin | 来源:发表于2017-05-27 12:01 被阅读0次

    本文译自《Architecture of SQLite》

    介绍

    这篇文档描述了SQLite库的架构。如果想理解SQLite内部原理,或者对它进行修改,这篇文档提供了有帮助的信息。

    下图展示了SQLite的主要组件和它们的协作方式。后文解释了这些组件的具体职责。

    SQLite模块

    本文中各组件的原文译文对照:

    原文 译文
    Interface 接口
    SQL Command Processor SQL命令处理器
    Virtual Machine 虚拟机
    Tokenizer 词法分析器
    Parser 语法分析器
    B-Tree B树
    Pager 页缓存
    OS Interface OS接口
    Utilities 通用库
    Test Code 测试代码

    概览

    SQLite的工作流程是将SQL文本编译成字节码,然后在虚拟机上运行这些字节码。

    sqlite3_prepare_v2()和相关的接口起到编译器的作用,将SQL文本转化为字节码。sqlite3_stmt对象是一个字节码容器,存储了单条SQL语句所编译出的字节码。sqlite3_step()接口将字节码程序传给虚拟机,执行字节码程序直到它完成、返回结果集、遇到严重错误或被中断(interrupted)。

    接口

    C语言接口主要在main.clegacy.cvdbeapi.c中,也有一些接口分散在其他文件中,这是为了使它们能使用一些文件私有的数据结构。sqlite3_get_table()例程在table.c中,sqlite3_mprintf()printf.c中,sqlite3_complete()tokenize.c中,TCL Interfacetclsqlite.c中。

    为避免名称冲突,SQLite库中的所有外部符号都以前缀sqlite3开头。那些用于外部使用的符号,也就是出现在SQLite API中的符号,会添加一个下划线,从而以sqlite3_开头。扩展API有时会在下划线之前添加扩展名,例如:sqlite3rbu_或sqlite3session_。

    词法分析器

    当一条SQL语句要被编译时,它首先被发送给词法分析器。

    词法分析器将SQL文本分解成词,然后将它一个个交给语法分析器。词法分析器的文件是tokenize.c,其中的代码是手工写的。

    注意此处的设计,是词法分析器调用语法分析器。熟悉YACC或者BISON的人可能习惯于反过来——让语法分析器调用词法分析器。前者更好,因为它可以做到线程安全,并且运行地更快。

    语法分析器

    语法分析器根据词的上下文赋予它语义。

    SQLite的语法分析器通过Lemon LALR(1)生成。Lemon的功能和YACC、BISON类似,但是它所使用的输入语法更不容易出错。同时Lemon生成的语法分析器是可重入和线程安全的。Lemon定义了“非终结符析构器(non-terminal destructor)”的概念,因此它在遇到语法错误时不会泄露内存。Lemon所需的语法文件是parse.y,其中定义了SQLite使用的SQL语法。

    因为Lemon很可能不在开发机器上,它完整的源代码在SQLite的tool文件夹中,仅有一个C文件。

    代码生成器

    语法分析器将词转化为语法树,代码生成器分析语法树,并且生成符合SQL功能的字节码。

    prepared statement对象是这段字节码的容器。代码生成器包含很多文件:attach.c,** auth.cbuild.cdelete.cexpr.cinsert.cpragma.cselect.ctrigger.cupdate.cvacuum.cwhere.cwherecode.c以及whereexpr.c**。SQLite的魔法大多发生在这些文件中。

    expr.c处理表达式的代码生成,where.c处理SELECT,UPDATE,DELETE语句的WHERE子句的代码生成。attach.cdelete.cinsert.cselect.ctrigger.cupdate.c,和vacuum.c处理和文件名对应的SQL语句的代码生成,其中每个文件都需要调用expr.cwhere.c中的例程。其他所有的SQL语句都由build.c处理。auth.c*实现了sqlite3_set_authorizer()的功能。

    代码生成器,特别是where.cselect.c中的逻辑部分,有时被称作查询计划器query planner。对于任何一条SQL语句,可能有成百上千种不同的算法能得出结果。查询计划器是一个AI,尽力从其中选出最好的算法。

    字节码引擎

    生成器输出的代码最终由虚拟机来执行。

    虚拟机本身完全包含在单个文件中,即vdbe.c文件。vdbe.h头文件定义了其他SQLite库与虚拟机之间的接口,而vdbeInt.h定义了虚拟机私有的数据结构和接口。

    剩下的多个vdbe.c文件是虚拟机的辅助代码。vdbeaux.c文件包含了虚拟机使用的通用库,以及其他库用来构造VM程序的接口模块。vdbeapi.c文件包含了虚拟机的外部接口,比如sqlite3_bind_int()sqlite3_step()。单个值(字符串,整数,浮点数,二进制数据)存储在一个内部对象“Mem”中,该对象在vdbemem.c*实现。

    SQLite通过回调C语言来实现SQL的函数。甚至内置的SQL函数也通过这种方式实现。大部分内置SQL函数,例如abs()count()substr()等,都写在func.c文件中。日期时间转换函数写在date.c中。一些函数,例如coalesce()typeof()直接被代码生成器实现为字节码。

    B树

    SQLite使用B树结构来维护磁盘上的数据,B树的实现在btree.c文件中。

    数据库中每个表和索引都使用单独的B树。全部的B树都存储在同一个磁盘文件中。文件格式的规格是明确且稳定的,并且保证向前兼容。

    B树子系统对其他SQLite库的接口定义在头文件btree.h中。

    页缓存

    B树模块要求磁盘上的信息具有固定的页面大小。默认的页面大小(page_size)是4096字节,但是也可以设置为512到65536之间的2的整数幂。页缓存负责页面的读写和缓存。页缓存也提供回滚和原子性提交的抽象,并且负责对数据库文件加锁。

    B树模块向页缓存请求页面,并且在修改页面,提交或回滚时通知页缓存。页缓存会处理大量的细节,以确保请求被快速,安全,高效地处理。

    主要的页缓存实现是在pager.c文件中,WAL模式的逻辑在单独的wal.c中,内存型缓存实现在pcache.cpcache1.c文件中。页缓存子系统对其他SQLite库的接口定义在pager.h中。

    OS接口

    为了提供跨操作系统移植性,SQLite使用名为VFS的抽象对象。每个VFS提供对磁盘文件的打开、关闭以及读写方法,以及其他特定于操作系统的功能,如获得当前时间,为伪随机数生成器设置随机种子等。

    SQLite目前对unix和Windows提供VFS,分别在os_unix.cos_win.c文件中。

    通用类

    内存分配,大小写不敏感的字符串比较例程,可移植的字符串到数字转换例程,以及其他通用库位于util.c中。

    hash.c实现了哈希表结构,在语法解析器中被用作符号表。utf.c源文件包含Unicode转换的相关例程。在printf.c中,SQLite实现了自己私有的printf(),包含了一些拓展。在random.c中,SQLite也实现了自己的伪随机数生成器。

    测试代码

    在src文件夹中,以test开头的文件为测试代码,不被包含在标准库版本中。

    相关文章

      网友评论

          本文标题:SQLite架构

          本文链接:https://www.haomeiwen.com/subject/spaffxtx.html