[翻譯] SQLite架構

本翻譯版本謝絕轉載!

SQLite架構

介紹

本文描述了SQLite庫的架構。本文信息對哪些想要理解或修改SQLite內部工作內容的人非常有用。

附圖展示了SQLite的主要組件以及他們是如何相互操作的。其下的文字解釋了各個組件的角色。

Overview總覽

SQLite 先編譯SQL文本爲字節碼bytecode, 然後使用虛擬機來運行字節碼(bytecode)來工作。

sqlite3_prepare_v2()以及相關接口扮演着編譯器的角色,將SQL文本轉換成字節碼。 sqlite3_stmt 對象是一個容器。該容器用於包含一個實現單獨SQL語句的獨立的字節碼程序。 sqlite3_step() 接口向虛擬機傳遞字節碼程序, 並執行字節碼程序直到完成,或返回產生的一行結果,或碰到一個致命fatal錯誤, 或被打斷interrupted.

Interface接口

大部分的C語言接口C-language Interface 在 main.clegacy.c, and vdbeapi.c 這些源文件中被找到,儘管一些程序被分散在其他可以通過文件域訪問數據結構的文件中。sqlite3_get_table()程序在 table.c 中實現.sqlite3_mprintf() 程序在 printf.c 中實現。sqlite3_complete() 接口在 tokenize.c 中. TCL Interface 在 tclsqlite.c 中實現.

爲了避免命名衝突,SQLite庫的所有的外部(external)符號都使用 sqlite3 前綴。那些用於外部使用的(換句話說,那些符號形成了SQLite的API)符號增加下劃線,因此以 sqlite3_ 開頭。 擴展API有時候在下劃線前增加擴展名;例如: sqlite3rbu_ 或 sqlite3session_

Tokenizer分詞器

當一個包含SQL句子的字符串被計算時,它首先會被髮送到tokenizer(分詞器)。tokenizer將SQL文本拆分成tokens(詞),然後將token一個接一個傳遞給parser(解析器)。tokenizer編碼在tokenize.c文件中。 注意在這個設計中,tokenizer調用parser。熟悉YACC和BISON的人可能習慣用相反的方式-讓parser調用tokenizer。讓tokenizer調用parser的方式更好一些,因爲這樣能夠線程安全,並且執行的更快。

Parser解析器

parser(解析器)根據上下文爲token賦予意思。SQLite的parser通過Lemon parser generator生成。Lemon和YACC/BISON做同樣的事情,但是它使用另一種不容易出錯的輸入語法。Lemon同時一個可重入的,線程安全的parser。Lemon定義了一個(non-terminal destructor)非終端析構的概念,因此在遇到語法錯誤時它不會內存泄漏。在parse.y中找到執行Lemon的語法文件和SQLite理解SQL語言的定義。 因爲Lemon這個程序一般不會在開發機器上找到,所以Lemon完整的源代碼(就一個C文件)被包含在SQLite分發的「tool」子目錄中。

Code Generator代碼生成器

在parser將token裝配成parse樹後,代碼生成器開始分析parse樹,生成執行SQL語句工作的字節碼bytecodeprepared statement 對象是包含了這些字節碼的容器。 代碼生成器有很多文件,包含: attach.cauth.cbuild.c,delete.cexpr.cinsert.cpragma.cselect.ctrigger.cupdate.cvacuum.cwhere.cwherecode.c, and whereexpr.c. 大部分重要的魔法發生在這些文件中。 expr.c 操縱着代碼生成器的表達。 where.c* 操縱代碼生成器處理SELECT,UPDATE和DELETE的WHERE從句。attach.cdelete.cinsert.cselect.ctrigger.c update.c, and vacuum.c 這幾個文件操縱代碼生成器處理和文件名同名的SQL語句。(所有這些文件必要時在expr.c 和 where.c中調用)所有其他SQL語句被編寫在 build.c. auth.c 文件實現了 sqlite3_set_authorizer()的功能。

代碼生成器,尤其時在where*.c 和 select.c中的邏輯,有時候被稱爲查詢計劃 query planner。對於任何具體的SQL語句,可能有成千上百個不同的算法來計算結果。查詢計劃query planner時一個力求從這麼多算法中選擇一個最好的算法的人工智能。

Bytecode Engine

字節碼bytecode 程序代碼生成器生成,運行在虛擬機上。 虛擬機自身完整地包含在單獨的 vdbe.c源文件中。vdbe.h頭文件在虛擬機和剩餘的SQLite庫之間定義了接口, vdbeInt.h 定義的結構和接口是虛擬機自己私有的。其他幾個vdbe*.c文件是虛擬機的助手(helpers)。vdbeaux.c 文件包含虛擬機使用的有效工具和剩餘SQLite庫用於構建VM程序的接口模塊。vdbeapi.c 文件包含虛擬機的擴展接口,如 sqlite3_bind_int() 和 sqlite3_step()。獨立的值 (strings, integer, floating point numbers, and BLOBs) 被存儲在由vdbemem.c實現,命名爲「Mem」的內部對象中。

SQLite使用C語言程序的callbacks來實現SQL函數。即使內置的SQL函數也是這個方式實現。大部分內置SQL函數(如: abs()count()substr(), 等等) 能夠在 func.c 源文件中找到。日期和時間轉換函數在 date.c中找到。 一些函數如coalesce() 和 typeof() 由代碼生成器直接生成字節碼實現。

B-Tree

SQLite數據庫使用B-tree來保持數據到磁盤,在源文件btree.c中實現。在數據庫中的每個表和索引使用單獨的B-tree。所有的B-tree存儲在同一個磁盤文件中。文件格式file format 詳情是穩定的、明確的、在更新中保證兼容性的。

B-tree子系統和其他SQLite庫的交互接口在頭文件btree.h中定義。

Page Cache頁緩存

B-tree模塊以固定大小的頁向磁盤請求信息。默認的頁大小page_size是4096字節,也可以是512字節和65525字節之間任意的2的n次冪。頁緩存(page cache)負責讀、寫、緩存這些頁。頁緩存同時提供回滾和原子提交的抽象,同時負責鎖定數據庫文件。B-tree驅動從頁緩存請求指定的頁,當它想修改頁、或提交、或回滾修改時,通知頁緩存。頁緩存確保快速、安全、高效地處理請求的所有混雜細節。 基本的頁緩存在pager.c文件中實現。WAL mode邏輯在單獨的wal.c中。內存緩存(in-memory caching)在 pcache.c 和 pcache1.c文件中實現。在pager.h頭文件中,實現了頁緩存子系統和SQLite庫剩餘的其他系統交互的接口。

OS Interface

SQLite使用抽象的 VFS對象,提供在不同操作系統間的移植能力。每個VFS提供了打開(opening)、讀(read)、寫(writing)和關閉(closing)磁盤上的文件的方法; 提供具體的操作系統任務,比如查找當前時間,獲取隨機數用來初始化內置的僞隨機數生成器。SQLite當前版本爲unix在os_unix.c文件提供VFS,爲windows在os_win.c文件提供VFS。

Utilities

內存分配,無大小寫字符串比較程序,可移植的文本轉數字程序,以及其他工具在util.c文件中。在解析器使用的符號表使用hash.c中的hash表來存儲。utf.c源文件包含了Unicode轉換子程序。SQLite在printf.c有自己私有的printf()實現,包含了一些擴展。SQLite在random.c中有自己的僞隨機數生成器(PRNG)

Test Code

在"src/"文件夾中,那些以test開頭的源文件是用來做測試的,不會被包含在構建的庫中。

轉載於:https://my.oschina.net/purely/blog/3006011