mavibot btree實現原理

Mavibot 是個Java 的多版本併發控制 BTree,是 JDBM(當前 Apache Directory 服務器的後端)的替代品, 但是有着更強的功能,能適應任意需要實現 Java MVCC BTree 的項目。Btree是在紅黑樹的基礎上提出的。紅黑樹的高度,限制了其性能。而Btree則通過擴展節點的存儲功能,降低了樹的高度。

1 紅黑樹(平衡二叉樹)

內存索引的文章中已經對平衡二叉樹進行了描述。這裏注意兩點:
第一點: 平衡二叉樹的高度,影響了插入、查詢的效率。維護的數據越多,二叉樹的高度越高,插入數據和查詢數據的比較次數就越多。最理想的效率是進行log2n次的數據比較(n是數據個數。在完全二叉樹的情況下。)
第二點:併發控制。平衡二叉樹,爲了維護平行特性,需要交換子樹的父子節點關係。如果當前的子樹高度發生了變化,那麼子樹所在的父節點也需要balance操作(當然,如果左右子樹的高度相差小於等於1,就不需要進行交換擦做。)這麼說來,插入一個節點,可能會導致根節點發生變化。從這個角度來講,平衡而插入的併發插入需要給整棵樹加鎖,也就是說插入是串行的。在不改進二叉樹的算法情況下(目前還不瞭解怎麼改進二叉樹算法,從而滿足併發),插入的性能是無法優化的。

2 B-Tree

目前幾乎所有的數據庫索引都採用了B樹結構。在平衡二叉樹的基礎上,B樹每一層的數據量更多,所以樹的高度降低,加快了查詢和插入的效率。
B-Tree組織結構如下圖:
在這裏插入圖片描述
TreeNode不存儲數據,只負責檢索。TreeLeaf存儲了所有的數據。TreeLeaf中,key和value分別爲兩個數組。相同的位置,對應一對<key,value>.

在併發的角度來看,B樹依舊很難線程安全。
下圖是mavibot的BTree添加數據的算法。再添加的過程中,一個樹節點的元素個數超出了限制,就需要對節點進行分裂操作。
當新的數據到來時,將數據插入葉子節點中。此時發現葉子節點的數據量已經超過限制,則對葉子節點進行分割,形成兩個節點。葉子節點將分裂的信息傳遞給根節點。根節點原來有一個position的信息指向葉子節點。但是目前葉子節點分裂成兩個,所以根節點需要新建立一個新的position指向另外一個葉子節點。根節點將position之後的所有數據向後移一位,然後在position+1的位置存儲新葉子的信息。實際上相當於根節點也增加了一個數據。
在一定條件下,一個葉子節點發生分裂時,可能導致整棵樹的高度變化。(沿着路徑,所有的節點都發生了分裂,那麼根節點就會分裂成兩個。爲了保證一棵樹只有一個根節點,需要生成一個新的根節點,作爲整棵樹的根。)
所以,和平衡二叉樹的情況類似,添加一個元素可能會導致整棵樹的組織結構發生變化。如果想併發構建這棵樹,就需要給整棵樹加同步。
在這裏插入圖片描述

3 多版本控制(MVCC)

在mavibot中通過多版本控制的方式,達到讀寫併發、事物、回滾的功能。多版本可以保證在修改的時候,不會影響查詢,保證查詢的效率。但是無法支持併發寫。
下面以插入爲例,介紹多版本控制的實現方式。
當插入請求發起,mavibot會創建一個新根節點,指向當前的樹。通過新樹查找對應的葉子節點。找到葉子節點後,將複製當前葉子同時插入新元素。
完成後,將新的葉子節點返回給parent。這時,current樹並沒有發生變化。
上一級的父節點TreeNode接到返回結果後,會將本身拷貝出一個新的節點,然後返回新的節點。按此方式處理,直到根節點。
從而,從根節點到插入元素的葉子節點的路徑上,所有節點都會拷貝出一個新的對象。而不在路徑上的節點,保持不變。這樣就以最快的速度複製出一個新的版本來。
總的來說,在多版本控制方式下,插入新的元素,需要將元素所在的葉子節點和根節點的路徑上所有節點進行了複製。而非路徑上的節點不會發生變化。通過此種方式,保證了插入時不影響讀操作,同時也降低了完全備份帶來的時間和空間的消耗。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章