SQLite的体系结构简介(zt)
<script></script>标签:知识/探索 | ? |
这篇文档主要描述了SQLite类库的结构。这篇文档的内容对于那些想了解和修改SQLite内部结构的人将会非常有用。
右侧是一个结构图,它显示了SQLite的主要成分及各成分之间是如何相互关联的。接下来的文本将简要的介绍每个单一的成分。
这篇文档描述SQLite第三版,它和 2.8版以及早期的版本基本相似,但在一些细节上是有区别的。
接口程序
SQLite类库大部分的公共接口程序是由main.c, legacy.c, 和 vdbeapi.c源文件中的功能执行的。但有些程序是分散在其他文件夹的,因为在其他文件夹里他们可以访问有文件作用域的数据结构。 sqlite3_get_table() 这个程序是在table.c中执行的。 sqlite3_mprintf()在printf.c中执行。 sqlite3_complete()在tokenize.c中执行。 Tcl 接口程序用tclsqlite.c来执行。
为了避免和其它软件在名字上有冲突,SQLite类库中所有的外部符号都是以sqlite3为前缀来命名的。这些被用来做外部使用的符号(换句话说,这些符号用来形成SQLite的API)是以sqlite3_.
来命名的。Tokenizer
当执行一个包含SQL语句的字符串时,接口程序要把这个字符串传递给tokenizer。Tokenizer的任务是把原有字符串分成一个个标示符,并把这些标示符传递给剖析器。Tokenizer是在C文件夹tokenize.c中用手编译的。
在这个设计中需要注意的一点是,tokenizer调用parser。熟悉YACC和BISON的人们也许会习惯于用parser调用 tokenizer。 The author of SQLite的作者已经尝试了这两种方法,并发现用tokenizer调用parser会使程序运行的更顺利。YACC使程序更滞后一些。
Parser
The parser是一个部分,它基于文件场景赋予tokens意思。SQLite的parser是由 Lemon LALR(1) parser generator产生的。Lemon和YACC/BISON一样做同样的工作,但是它使用不同的输入语句,这个输入语句是不易出错的。 Lemon也产生一个parser,这个parser是可重入的并且是线程安全的。 Lemon 定义了无终端解除程序的概念,所以当遇到语法错误的时候,它不会泄露内存。驱动Lemon的原文件在parse.y.
因为lemon是一个在发展机械上不常见的程序,所以lemon的源代码(只是一个C文件)是在SQLite分布区的"tool"子目录下的。 lemon的文档是在分布区的 "doc"子目录下的。
代码发生器
在剖析器收集完符号并把之转换成完全的SQL语句时,它调用代码产生器来产生虚拟的机器代码,这些机器代码将按照SQL语句的要求来工作。在代码产生器中有许多文件; attach.c, auth.c, build.c, delete.c, expr.c, insert.c, pragma.c, select.c, trigger.c, update.c, vacuum.c and where.c. 正是在这些文件中,最具有重要意义的事情发生了。 expr.c 处理表达式代码的生成。 where.c 处理SELECT, UPDATE and DELETE语句中WHERE子句的代码的生成。文件 attach.c, delete.c, insert.c, select.c, trigger.c update.c,和vacuum.c处理SQL语句中具有同样名字的语句的代码的生成。(每个文件调用expr.c and where.c中的程序) All other 所有SQL的其它语句的代码是由build.c生成的。文件auth.c 执行sqlite3_set_authorizer()的功能.
虚拟机器
由代码生成器产生的程序由虚拟机器来运行。总而言之,虚拟机器主要用来执行一个为操作数据库而设计的抽象的计算引擎。机器有一个用来存储中间数据的存储栈。每个指令包含一个操作代码和三个额外的操作数。
虚拟机器本身是被包含在一个单独的文件vdbe.c中的。虚拟机器也有它自己的标题文件:vdbe.h它在虚拟机器和剩下的SQLite类库之间定义了一个接口程序,vdbeInt.h 它定义了虚拟机器的结构。文件vdbeaux.c包含了虚拟机器所使用的实用程序和一些被其它类库用来建立VM程序的接口程序模块。文件vdbeapi.c 包含虚拟机器的外部接口,比如 sqlite3_bind_... 类的函数。单独的值(字符串,整数,浮动点数值,BLOBS)被存储在一个叫 "Mem"的内部目标程序里,"Mem"是由vdbemem.c执行的。
SQLite使用C语言程序来来执行SQL函数。即使内置的SQL函数也是用这种方法来执行的。大部分的SQL内置函数(ex: coalesce(), count(),substr(), and so forth)可以在func.c里发现。日期和时间转换函数在date.c.
B-树
SQLite数据库在磁盘里维护,使用源文件btree.c中的B-树执行。数据库中的每个表格和目录使用一个单独的B-tree。所有的 B-trees 被存储在同样的磁盘文件里。文件格式的细节被记录在btree.c.
开头的备注里。B-tree子系统的接口程序被标题文件btree.h所定义。.
页面高速缓存
B-tree模块要求信息来源于磁盘上固定规模的程序块。默认程序块的大小是1024个字节,但是可以在512和65536个字节间变化。页面高速缓存负责读,写和高速缓存这些程序块。页面高速缓存还提供重新运算和提交抽象命令,它还管理关闭数据库文件夹。 B-tree驱动器要求页面高速缓存器中的特别的页,当它想修改页或重新运行改变的时候,它会通报页面高速缓存。为了保证所有的需求被快速,安全和有效的处理,页面高速缓存处理所有的微小的细节。
运行页面高速缓存的代码在专门的C源文件pager.c中。页面高速缓存的子系统的接口程序被目标文件pager.h所定义。
OS 接口程序
为了在POSIX和Win32 之间提供一些可移植性,SQLite操作系统的接口程序使用一个提取层。 OS提取层的接口程序被定义在os.h. 每个支持的操作系统有它自己的执行文件: Unix使用os_unix.c,windows使用os_win.c。每个具体的操作器具有它自己的标题文件: os_unix.h, os_win.h, etc.
Utilities
内存分配和字符串比较程序位于util.c。剖析器使用的表格符号被hash.c中的无用信息表格维护。源文件utf.c包含UNICODE转换子程序。SQLite有它自己的执行文件printf() (有一些扩展)在printf.c中,还有它自己随机数量产生器在random.c.
测试代码
如果你计算回归测试脚本,多于一半的SQLite代码数据库的代码将被测试。在主要代码文件中有许多assert()语句。另外,源文件test1.c通过test5.c和md5.c 执行只为测试用的扩展名。os_test.c向后的接口程序用来模拟断电,来验证页面调度程序中的系统性事故恢复机制。