SQLite的體系結(jié)構(gòu)
下圖是一個(gè)體系結(jié)構(gòu)圖,顯示了SQLite的主要組件以及各組件之間是如何相互關(guān)聯(lián)的。
在內(nèi)部,SQLite由以下幾個(gè)組件組成:內(nèi)核、SQL編譯器、后端以及附件。SQLite通過利用虛擬機(jī)和虛擬數(shù)據(jù)庫引擎(VDBE),使調(diào)試、修改和擴(kuò)展SQLite的內(nèi)核變得更加方便。所有SQL語句都被編譯成易讀的、可以在SQLite虛擬機(jī)中執(zhí)行的程序集。SQLite支持大小高達(dá)2 TB的數(shù)據(jù)庫,每個(gè)數(shù)據(jù)庫完全存儲在單個(gè)磁盤文件中。這些磁盤文件可以在不同字節(jié)順序的計(jì)算機(jī)之間移動(dòng)。這些數(shù)據(jù)以B+樹(B+tree)數(shù)據(jù)結(jié)構(gòu)的形式存儲在磁盤上。SQLite根據(jù)該文件系統(tǒng)獲得其數(shù)據(jù)庫權(quán)限。
1、公共接口(Interface) SQLite庫的大部分公共接口由main.c, legacy.c和vdbeapi.c源文件中的函數(shù)來實(shí)現(xiàn),這些函數(shù)依賴于分散在其他文件中的一些程序,因?yàn)樵谶@些文件中它們可以訪問有文件作用域的數(shù)據(jù)結(jié)構(gòu)。sqlite3_get_table()例程在table.c中實(shí)現(xiàn),sqlite3_mprintf()可在printf.c中找到,sqlite3_complete()則位于tokenize.c中。Tcl接口在tclsqlite.c中實(shí)現(xiàn)。SQLite的C接口信息可參考http:///capi3ref.html。 為了避免和其他軟件的名字沖突,SQLite庫的所有外部符號都以sqlite3為前綴,這些被用來做外部使用的符號(換句話說,這些符號用來形成SQLite的API)是以sqlite3_開頭來命名的。
2、詞法分析器(Tokenizer) 當(dāng)執(zhí)行一個(gè)包含SQL語句的字符串時(shí),接口程序要把這個(gè)字符串傳遞給tokenizer。Tokenizer的任務(wù)是把原有字符串分割成一個(gè)個(gè)標(biāo)識符(token),并把這些標(biāo)識符傳遞給解析器。Tokenizer是用手工編寫的,在C文件tokenize.c中。 在這個(gè)設(shè)計(jì)中需要注意的一點(diǎn)是,tokenizer調(diào)用parser。熟悉YACC和BISON的人們也許會習(xí)慣于用parser調(diào)用tokenizer。SQLite的作者已經(jīng)嘗試了這兩種方法,并發(fā)現(xiàn)用tokenizer調(diào)用parser會使程序運(yùn)行的更好。YACC會使程序更滯后一些。
3、語法分析器(Parser)
語法分析器的工作是在指定的上下文中賦予標(biāo)識符具體的含義。SQLite的語法分析器使用Lemon LALR(1)分析程序生成器來產(chǎn)生,Lemon做的工作與YACC/BISON相同,但它使用不同的輸入句法,這種句法更不易出錯(cuò)。Lemon還產(chǎn)生可重入的并且線程安全的語法分析器。Lemon定義了非終結(jié)析構(gòu)器的概念,當(dāng)遇到語法錯(cuò)誤時(shí)它不會泄露內(nèi)存。驅(qū)動(dòng)Lemon的源文件可在parse.y中找到。 因?yàn)閘emon是一個(gè)在開發(fā)機(jī)器上不常見的程序,所以lemon的源代碼(只是一個(gè)C文件)被放在SQLite的"tool"子目錄下。 lemon的文檔放在"doc"子目錄下。
4、代碼生成器(Code Generator)
語法分析器在把標(biāo)識符組裝成完整的SQL語句后,就調(diào)用代碼生成器產(chǎn)生虛擬機(jī)代碼,以執(zhí)行SQL語句請求的工作。代碼生成器包含許多文件:attach.c, auth.c, build.c, delete.c, expr.c, insert.c,pragma.c, select.c, trigger.c, update.c, vacuum.c和where.c。這些文件涵蓋了大部分最重要、最有意義的事情。expr.c處理SQL中表達(dá)式的代碼生成。where.c處理SELECT、UPDATE和DELETE語句中WHERE子句的代碼生成。文件attach.c, delete.c, insert.c, select.c, trigger.c, update.c和vacuum.c處理同名SQL語句的代碼生成(這些文件在必要時(shí)都調(diào)用expr.c和where.c中的例程)。所有其他SQL語句的代碼由build.c生成。文件auth.c實(shí)現(xiàn)sqlite3_set_authorizer()的功能。
5、虛擬機(jī)(Virtual Machine)
代碼生成器生成的代碼由虛擬機(jī)來執(zhí)行。關(guān)于虛擬機(jī)更詳細(xì)的信息可參考http:///opcode.html。總的來說,虛擬機(jī)實(shí)現(xiàn)一個(gè)專為操作數(shù)據(jù)庫文件而設(shè)計(jì)的抽象計(jì)算引擎。它有一個(gè)存儲中間數(shù)據(jù)的存儲棧,每條指令包含一個(gè)操作碼和不超過三個(gè)額外的操作數(shù)。 虛擬機(jī)本身被完整地包含在一個(gè)單獨(dú)的文件vdbe.c中,它也有自己的頭文件,其中vdbe.h定義虛擬機(jī)與SQLite庫其他部分之間的接口,vdbeInt.h定義虛擬機(jī)私有的數(shù)據(jù)結(jié)構(gòu)。文件vdbeaux.c包含被虛擬機(jī)使用的一些工具,和被庫的其他部分用來構(gòu)建VM程序的一些接口模塊。文件vdbeapi.c包含虛擬機(jī)的外部接口,例如sqlite3_bind_...族的函數(shù)。單獨(dú)的值(字符串、整數(shù)、浮點(diǎn)數(shù)、BLOB對象)被存儲在一個(gè)叫Mem的內(nèi)部對象中,在vdbemem.c中可找到它的實(shí)現(xiàn)。 SQLite使用回調(diào)風(fēng)格的C語言程序來實(shí)現(xiàn)SQL函數(shù),每個(gè)內(nèi)建的SQL函數(shù)都用這種方式來實(shí)現(xiàn)。大多數(shù)內(nèi)建的SQL函數(shù)(例如coalesce(), count(), substr(), 等等)可在func.c中找到。日期和時(shí)間轉(zhuǎn)換函數(shù)可在date.c中找到。
6、B-樹(B-Tree) 一個(gè)SQLite數(shù)據(jù)庫使用B-樹的形式存儲在磁盤上,B-樹的實(shí)現(xiàn)位于源文件btree.c中。數(shù)據(jù)庫中的每個(gè)表和索引使用一棵單獨(dú)的B-樹,所有的B-樹存放在同一個(gè)磁盤文件中。文件格式的細(xì)節(jié)被記錄在btree.c開頭的備注里。B-樹子系統(tǒng)的接口在頭文件btree.h中定義。
7、頁面高速緩存(Page Cache) B-樹模塊以固定大小的數(shù)據(jù)塊形式從磁盤上請求信息,默認(rèn)的塊大小是1024個(gè)字節(jié),但是可以在512和65536個(gè)字節(jié)之間變化。頁面高速緩存負(fù)責(zé)讀、寫和緩存這些數(shù)據(jù)塊。頁面高速緩存還提供回滾和原子提交的抽象,并且管理數(shù)據(jù)文件的鎖定。B-樹驅(qū)動(dòng)模塊從頁面高速緩存中請求特定的頁,當(dāng)它想修改頁面、想提交或回滾當(dāng)前修改時(shí),它也會通知頁面高速緩存。頁面高速緩存處理所有麻煩的細(xì)節(jié),以確保請求能夠快速、安全而有效地被處理。 頁面高速緩存的代碼實(shí)現(xiàn)被包含在單一的C源文件pager.c中。頁面高速緩存子系統(tǒng)的接口在頭文件pager.h中定義。
8、OS接口 為了在POSIX和Win32操作系統(tǒng)之間提供移植性,SQLite使用一個(gè)抽象層來提供操作系統(tǒng)接口。OS抽象層的接口在os.h中定義,每種支持的操作系統(tǒng)有各自的實(shí)現(xiàn):Unix使用os_unix.c,Windows使用os_win.c,等等。每個(gè)特定操作系統(tǒng)的實(shí)現(xiàn)通常都有自己的頭文件,如os_unix.h, os_win.h等。
9、實(shí)用工具(Utilities) 內(nèi)存分配和字符串比較函數(shù)位于util.c中。語法分析器使用的符號表用Hash表來維護(hù),其實(shí)現(xiàn)位于hash.c中。源文件utf.c包含Unicode轉(zhuǎn)換子程序。SQLite有自己的printf()實(shí)現(xiàn)(帶一些擴(kuò)展功能),在printf.c中,還有自己的隨機(jī)數(shù)生成器,在random.c中。
10、測試代碼(Test Code) 如果你計(jì)算回歸測試腳本,超過一半的SQLite代碼將被測試。主要代碼文件中有許多assert()語句。另外,源文件test1.c通過test5.c和md5.c實(shí)現(xiàn)只用于測試目的的一些擴(kuò)展。os_test.c后端接口用來模擬斷電,以驗(yàn)證頁面高速緩存的崩潰恢復(fù)機(jī)制。
|