热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SQLite架构

本文译自《ArchitectureofSQLite》介绍这篇文档描述了SQLite库的架构。如果想理解SQLite内部原理,或者对它进行修改,这篇文档提供了有帮助的信息。下图展示了

本文译自《Architecture of SQLite》

介绍

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

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

《SQLite架构》 SQLite模块

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

原文译文
Interface接口
SQL Command ProcessorSQL命令处理器
Virtual Machine虚拟机
Tokenizer词法分析器
Parser语法分析器
B-TreeB树
Pager页缓存
OS InterfaceOS接口
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 Interface在tclsqlite.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开头的文件为测试代码,不被包含在标准库版本中。


推荐阅读
author-avatar
人民总动员
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有