你也可以通過我的獨立部落格 —— www.huliujia.com 擷取本篇文章
背景
SkipList是LevelDB的MemTable使用的底層存儲結構,LevelDB實作了一個支援泛型的跳躍表。本文不會具體介紹跳躍表的資料結構,如果讀者不了解跳躍表的原理、實作,可以先看一下跳躍表(Skiplist)從原理到實作
SkipList的對外接口
Level對外隻提供了3個接口,構造、插入、查找。沒有提供删除接口,這個主要是因為LevelDB不會對SkipList的元素進行删除操作,整個SkipList的存儲會在MemTable被釋放時一起銷毀。這裡可以先不管MemTable,隻要知道SkipList最後會被整體删除就夠了。此外因為LevelDB的SkipList是用于存儲使用者寫入的key和value的,是以LevelDB的SkipList中不會也不允許有重複的元素。
下面是SkipList的部分代碼,隻展示了和對外接口相關的代碼
template<typename Key, class Comparator>
class SkipList
{
public:
explicit SkipList(Comparator cmp, Arena* arena);
void Insert(const Key& key);
bool Contains(const Key& key) const;
}
模闆參數
template<typename Key, class Comparator>
SkipList有兩個模闆參數,Key和Comparator。Key是SkipList要儲存的元素類型,Comparator是一個函數對象類型,用于比較兩個Key的大小。
構造函數
explicit SkipList(Comparator cmp, Arena* arena);
第一個參數cmp是一個Comparator函數對象的執行個體,用于比較大小。第二個參數arena是一個記憶體配置設定器,SkipList會使用arena來申請記憶體。Arena記憶體配置設定器我們在前面的文章 —— LevelDB源碼解析之Arena記憶體配置設定器介紹過。如果不了解的話,可以簡單了解為malloc。SkipList将從arena申請記憶體,而不是直接調用malloc申請記憶體。
Insert 和 Contains
void Insert(const Key& key);
字如其人,插入key,不解釋了。
bool Contains(const Key& key) const;
判斷SkipList是否包含key,包含就傳回true,反之傳回false。
Iterator
LevelDB還實作了一個Iterator,用于對SkipList進行尋址、周遊等操作。下面是具體的接口和作用。
class Iterator
{
public:
// 構造函數,構造後iterator指向的是一個無效節點。
explicit Iterator(const SkipList* list);
// 判斷目前節點(iterator指向的節點)是否是一個有效節點
bool Valid() const;
// 傳回目前節點的值。
const Key& key() const;
// 指向目前節點的下一個節點
void Next();
// 指向目前節點的前一個節點。
void Prev();
// 指向滿足 key >= target的最小節點
void Seek(const Key& target);
// 指向第一個有效節點(即不含頭結點的第一個節點)
void SeekToFirst();
// 指向最後一個有效節點
void SeekToLast();
private:
//Iterator所述的SkipList
const SkipList* list_;
//指向Iterator目前節點。
Node* node_;
};
SkipList的内部實作。
因為LevelDB的SkipList是結合LevelDB的使用場景,進行了簡化的SkipList,相當于是一個丐版SkipList。本文不會介紹具體的實作邏輯,關于SkipList的完整實作邏輯,可以看跳躍表(Skiplist)從原理到實作。這篇文章的跳躍表實作參考了LevelDB的實作,但是支援插入重複元素和删除元素。
LevelDB的SkipList通過next指針數組的方式來建構整個連結清單結構,避免了複制節點帶來的記憶體開銷和實踐開銷,也讓連結清單管理變得更為簡單。
此外,LevelDB在讀、寫next數組時,引入了原子變量用于同步,是線程安全的,可以支援多線程場景。
記憶體配置設定器
LevelDB的SkipList的記憶體管理使用了LevelDB自己開發的Arena記憶體配置設定器,以提高性能。Arena記憶體配置設定器的詳細介紹可以看這篇文章LevelDB源碼解析之Arena記憶體配置設定器
源碼版本
https://github.com/google/leveldb/releases/tag/1.22