Berkeley DB 1.8.6原始碼學習(一)
閱讀 Berdely DB 1.8.6 版。
基本資料結構
1、 資料庫
資料庫結構只含有兩個成員變數:
type : DBTYPE 型別,用於標示資料庫使用的資料型別,為列舉型別,列舉值可以為 DB_BTREE, DB_HASH, DB_RECNO ,分別表示 B 樹、雜湊表、 RECNO 演算法;
internal : void 型別指標,用於指向實際儲存資料的資料結構,就 B+ 樹來講,指向 B+ 樹結構;
資料庫的成員變數:
close :關閉資料庫;
del :刪除資料庫;
get :根據關鍵字獲取一條記錄;
put :寫入 / 更新一條記錄;
seq :順序遍歷;
sync :緩衝池與永久儲存器中的資料同步,即將資料寫入硬碟;
fd :獲取資料庫檔案描述符,記憶體資料庫沒有檔案描述符。
資料節點:資料節點用於在程式中傳遞關鍵字 / 資料的結構,有兩個成員變臉,
data : void 型別指標,存放資料內容;
size : size_t 型別, data 的長度;
B 樹基本資訊結構:含有 6 個成員變數和 2 個成員函式,記錄 B 樹的基本屬性。
flags :無符號 long 型別,表示資料庫是否支援多條記錄具備同一個關鍵字;
cachesize :無符號 int 型,可緩衝的位元組數;
maxkeypage : int 型,每頁可含有最大鍵的個數;
minkeypage : int 型,每頁必須含有鍵數量的最小值;
psize :無符號 int 型,頁面的大小;
lorder : int 型,記錄機器的位元組順序,即大小端;
成員變數:
compare :鍵的比較函式;
prefix :鍵的字首比較函式,使用可以提高查詢的效能;
以上資料結構是 db.h 中的資料結構。
2、 緩衝池
緩衝池用於緩衝資料庫檔案在記憶體中的資料,以記憶體頁為單位;具有 8 個成員變數:
lqh : lru ( Least Recently Used ,最近最久未使用演算法)佇列頭;
hqh :雜湊表;
curcache :當前緩衝頁的編號;
maxcache :緩衝頁的最大編號;
npages :資料庫檔案含有頁的數量;
pagesize :檔案頁的大小;
fd :資料庫檔案描述符;
pgcookie :指向具體的資料庫結構,譬如 B 樹;
2 個成員函式:
pgin :資料匯入時處理位元組大小端問題;
pgout :資料匯出時處理大小端問題;
頁面節點:頁面節點用於儲存頁面資訊,是緩衝池的 lqh 和 hqh 操縱的物件,含有 5 個成員變數,
hq :雜湊佇列,用於連線的結構體;
q : lru 佇列,用於連線的結構體;
page : void 型別指標,指向頁面的實際記憶體地址;
pgno :頁面編號;
flags :頁面的狀態,已修改(需寫回)、正訪問、備使用;
以上資料結構是 mpool.h 中的資料結構。
3、 B 樹
記憶體頁結構:用於記錄記憶體頁的資訊,位於頁面的開頭部分,含有 7 個成員變數:
pgno :頁面編號;
prevpg :左兄弟;
nextpg :右兄弟;
flags :頁面型別;
lower :空閒區低端指標;
upper :空想區高階指標;
linp :頁面儲存實際資料的索引起點;
關於記憶體頁需要關注其具體的部署,上述資料結構儲存於頁面的開始部分,從 linp 到頁面結束用於儲存實際的資料,同時這部分分為三個部分,靠近頁面開始的部分,即 linp 開始的部分是索引區,從頁面的最高階,即頁面結束的地址,向頁面開始方向是資料區,中間的部分是空閒區,空閒區使用 lower 和 upper 劃定區間,即如果以 END 標示頁面的最高地址 — 結束地址,則 linp-- ( *lower )是索引區,( *lower ) -- ( *upper )是空閒區,( *upper ) --END 是資料區;當向頁面中寫入資料時,首先按照資料的大小在空閒區分配相應的區間,分配方式是將( *upper )向( *lower )方向移動待存入資料大小的空間,然後,將此事 upper 指向的地址記錄下來,即索引的值,這就需要為索引分配一個記憶體空間,分配的方式是將( *lower )向( *upper )方向移動存放地址的空間。如此完成了對儲存資料的分配,對資料的訪問通過 linp[] 即可取出對應的 index 的值,從而訪問需要的資料。至於訪問時如何知道資料的大小,資料的開始 4 個位元組構成的無符號整數記錄的資料的實際大小。
B 樹內部結點:有四個成員變數,
ksize :鍵的大小;
pgno :所在頁面的編號;
flags :儲存的資料型別,大資料、大鍵值;
bytes :具體資料的起始地址;
說明:在儲存時結點的後面就是資料的值,這樣一個結點實際佔有的記憶體就是被解構的大小加上 ksize 的值;
B 樹葉子結點:有四個成員變數,
ksize :鍵的大小;
dsize :資料的大小;
flags :資料型別,大資料、大鍵值;
bytes :儲存資料 / 鍵內容的起始地址;
說明:實際的內容接在上述結構的後面,首相存放的是鍵的值,之後存放的是資料的值,由於葉子結點中使用 ksize 和 dsize 分別記錄鍵值和資料值的長度,所以不用擔心二者的定址,這樣葉子節點的大小就是結點的大小加上 ksize 和 dsize 。
記錄定址結構:用於儲存傳遞記錄的定址資訊,含有兩個成員變數,
pgno :記錄所在頁面的編碼;
index :記錄在頁面中的位置;
說明:從上面頁面結構、內部結點結構和葉子結點結構的分析可知,一條記錄要麼指向一個頁面(內部結點),要麼就是實際的資料。
記錄定址結構 2 :含有兩個成員變數,
page :頁面指標;
index :記錄在頁面中的位置;
說明:與上一個結構使用的場合不同。
遊標:含有四個成員變數,
pg :遊標停留的頁面編號;
key :鍵值;
rcursor :遊標指向的記錄索引;
flags :遊標的狀態;
B 樹元資料結構:儲存 B 樹的元資料資訊,含有 6 個成員變數,
magic :魔數;
version :版本資訊;
psize :頁面大小;
free :空閒頁面連結串列,記錄第一個空閒頁面的編號;
nrecs :
flags :樹性質,是否支援多條記錄只用相同的鍵,是否是 RECNO ;
說明:資料庫檔案的第 0 頁的開始部分存放著 B 樹元資料結構,本頁的剩餘部分空閒;
B 樹結構:
成員變數:
bt_mp :緩衝池;
bt_dbp :指向資料庫結構的指標;
bt_cur :當前正使用的頁面編號;
bt_pinned :正被其他函式使用的頁面;
bt_cursor :遊標;
bt_stack :訪問頁面的祖先結點棧;
bt_sp :棧指標;
bt_rkey :一些操作返回記錄暫時存放的鍵值;
bt_rdata :一些操作返回記錄暫時存放的資料值;
bt_fd :樹的檔案描述符;
bt_free :下一個空閒頁;
bt_psize :頁面大小;
bt_ovflsize :大資料的標準;
bt_lorder :位元組順序;
bt_order :順序遍歷方向:未設定、向後、向前;
bt_last :最近插入的頁面;
flags :樹的屬性,是否支援鎖功能等;
成員函式:
bt_cmp :鍵值比較函式;
bt_pfx :字首比較函式;