memtable是leveldb的核心資料結構之一,它的底層實作是skiplist,是一個記憶體層面的容器,負載主要的寫需求。
skiplist其實一個一個多層次連結清單,在查找時,先在最後層次進行查找,找到比較大的資料時就往低層次退,
skiplist有幾個主要底層的函數:
findgreaterorequal
keyisafternode
insert
findlessthan
findlast
randomheight
實際上skiplist的對外api seek的主要實作就是findgreaterorequal,
findgreaterorequal包攬了幾乎所有的邏輯,因為在插入和查找時,都需要先進行findgreaterorequal。
按照多層次的思想就很容易了解findgreaterorequal。
標明skiplist的最高層(l5)。
從標明層(l5)開始直接跳到>= k43的位置。
以最終結果(紅色方格)的上一跳的元素(橙色方格)開始,退到下一層(l4)再進行跳躍。
重複步驟2直到找到跟k43相等的元素或者已經周遊完l1(最底層)為止。
從leveldb實作上需要注意findgreaterorequal(const key& key, node** prev)。
findgreaterorequal在周遊過程中會把圖中橙色方格的指針通通記錄到prev内,供insert步驟修改指針使用。
了解findgreaterorequal後,insert步驟也迎刃而解。
初始狀态
findgreaterorequal
插入完成
insert步驟實際上就是使用findgreaterorequal找到結果以後,再利用結果修改指針,插入資料,具體步驟:
使用randomheight生成新節點的層高(圖中是l6),按照這個層高new一個新node。
如果層高超過原有的最高層高,需要開辟新層次,直接把新層高指向null,如果沒有超過則忽略步驟2。
進行findgreaterorequal。
根據prev傳回的結果,修改prev裡所有的node的指針到新node,同時把新node的指針指向原有node指向的對象。
memtable主要作用是對skiplist,arena,comparator進行群組合和管理,功能函數上隻是屏蔽了底層操作,對使用者更加優雅,是以無需再次分析。
其中arena是leveldb自己實作的記憶體池,按一定對齊位元組配置設定,實作簡單,這裡不作具體分析。
memtable會對自身做一個refs計數,當refs為零的時候,memtable執行自行清理。
memtable在leveldb中所起到的作用是提供随機寫的一個容器,相當于一層在leveldb中的外層屏障,肩負最大的寫入壓力。
當memtable增長一定的記憶體時。leveldb會把它轉化為一個immutable_memtable,然後緊接着放到背景進行compaction操作,
使memtable裡面的資料落地。
至此,memtable的主要功能都分析完畢了。