深入 SQLite 后端:虚拟机、存储和构建过程
Source: Dev.to
虚拟机 (VDBE)
当前端完成编译后,会把字节码程序交给虚拟数据库引擎 (VDBE)。
字节码程序是:
- 一系列线性指令
- 每条指令包含一个操作码和最多五个操作数
- 按顺序执行,一次一条指令
该 VM 的行为类似于专为数据库操作设计的自定义 CPU,负责表扫描、值比较、光标管理以及事务语义的实现等工作。
树模块(B‑树存储)
SQLite 使用树结构来存储数据:
- 表 → B+ 树
- 索引 → B‑树
每个表和索引都有各自独立的树结构。实现代码位于:
btree.c– 树的逻辑btree.h– 公共接口
树模块支持搜索、插入、删除、更新以及结构性变更(例如创建或删除表和索引)。
Pager(页面管理器)
Pager 是一个关键组件,负责调解所有文件 I/O。树模块从不直接访问数据库文件,而是通过 Pager 请求固定大小的页面。
Pager 的主要职责:
- 读取和写入数据库页面
- 维护内存页面缓存
- 处理文件锁定
- 管理回滚日志(journal)
- 强制事务边界
实际上,Pager 同时充当 数据管理器、锁管理器、日志管理器 和 事务管理器。其源文件为:
pager.cpager.h
Pager 使 SQLite 能够在单个数据库文件上提供 ACID 保证。
lovestaco@i3nux-mint:~/pers/sqlite$ ll /home/lovestaco/pers/sqlite/bld/sqlite3
-rwxrwxr-x 1 lovestaco lovestaco 6.9M Jan 11 17:14 /home/lovestaco/pers/sqlite/bld/sqlite3
构建过程
SQLite 的构建过程体现了其自包含和可复现的哲学。整个过程分为六个主要步骤:
- 生成
sqlite3.h - 构建 SQL 解析器
- 生成 VM 操作码
- 生成操作码名称
- 生成 SQL 关键字表
- 编译库文件
在构建期间:
lemon.c生成parse.c和parse.hmkkeywordhash.c生成keywordhash.hawk与sed生成sqlite3.h、opcodes.h和opcodes.c
opcodes.h 为 VM 指令分配数值,而 opcodes.c 将操作码映射为人类可读的名称,便于调试和诊断。
现代发行版提供了一个合并文件 sqlite3.c,以及 sqlite3.h。使用合并文件的优势包括:
- 性能提升 5–10 %
- 更激进的编译器优化
- 构建过程更简化
- 更易嵌入到应用程序中
命令行工具还需要 shell.c。
小结
- SQL 被编译成字节码,由专门构建的 VM 执行。
- SQLite 通过数据库级锁实现可串行化执行。
- 日志机制保证原子性和恢复能力。
- 每个数据库都存放在单个本地文件中,由
sqlite_master锚定。
该架构模块化、层次清晰,且完全开源、属于公有领域。
展望
下一章节将更深入地探讨数据库和日志文件的存储结构,揭示 SQLite 磁盘布局是如何实现这些抽象的。
进一步资源
- 我的 SQLite 实验:
- FreeDevTools(开源开发工具中心):
参考:SQLite Database System: Design and Implementation. Sibsankar Haldar (n.d.).