OceanBase分散式儲存引擎公共模組——基礎資料結構

凌雲ali發表於2017-07-13

OceanBase分散式儲存引擎公共模組——基礎資料結構

1.雜湊表

為了提高隨機讀取效能,UpdateServer支援建立雜湊索引,這個雜湊索引結構就是LightlyHashMap,程式碼如下:

template <typename Key, typename Value>
class LightlyHashMap
{
public:
    //插入一個<key,value>對到雜湊表
    inline int insert(const Key& key, const Value& value);
    //根據key查詢value
    inline int get(const Key& key, const Value& value);
    //根據key刪除一個<key,value>對,如果value不為空,那麼,儲存刪除的值到value中
    inline int erase(const Key& key, Value& value = NULL);
private;
    struct  Node
    {
        Key key;
        Value value;
        union
        {
            Node* next;
            int64_t flag;
        };
    };
    Node* buckets_; //雜湊桶指標
    BitLock bit_lock_;//位鎖,用於保護雜湊桶
};

LightlyHashMap採用鏈式衝突處理方法,即將所有雜湊值相同的對鏈到同一雜湊桶中,它包含如下三個方法:

  • insert:往雜湊表中插入一個對。這個函式首先根據key 的雜湊值得到桶號,接著,往雜湊桶中插入一個包含key和value值的Node節點。
  • get:根據key查詢value。這個函式首先根據key的雜湊值得到桶號,接著,遍歷對應的連結串列,找到與傳入key相同的Node節點,返回其中的value值。
  • erase:根據key刪除一個對。這個函式首先根據key的雜湊值得到桶號,接著,遍歷對應的連結串列,找到並刪除與傳入key相同的Node節點。

LightlyHashMap設計用來儲存幾千萬甚至幾億個元素,它與普通雜湊表的不同點在於以下兩點:

  1. 位鎖(BitLock):LightlyHashMap通過BitLock實現雜湊值的鎖結構,每個雜湊桶的鎖結構只需要佔用一個位(Bit)。如果雜湊桶對應的位鎖值為0.表示沒有鎖衝突;否則,表現出鎖衝突。需要注意的是,LightlyHashMap沒有區分讀鎖和寫鎖,多個get請求也是衝突。可以對LightlyHashMap的BitLock做一些改進,例如用兩個位(Bit)表示雜湊桶對應的鎖,其中一個位表示是否有讀衝突,另外一個位表示是否有寫衝突。
  2. 延遲初始化(Lazy Initialization):LightlyHashMap的雜湊桶個數往往特別多(預設為1000萬個),即使僅僅對所有雜湊桶執行一次memset操作,消耗的時間也是相當可觀的。因此,LightlyHashMap採用延遲初始化的策略,即將雜湊桶劃分為多個單元,預設情況下每個單元包含65536個雜湊桶。每次執行insert、get或者erase操作時都會判斷雜湊桶所屬的單元是否已經初始化,如果未初始化,則對該單元內的所有雜湊桶執行初始化操作。

2.B樹

UpdateServer的MemTable結構底層採用B樹結構索引其中的資料,程式碼如下:

template<class K, class V, class Alloc>
class BTreeBase
{
public:
    //把,<key, value>對加到B樹中,overwrite參數列示是否覆蓋原有值
    int put(const K& key, const V& value, const bool overwrite = false);
    //獲取key對應的value
    int get(const K& key, V& value);
    //獲取掃描操作描述符
    int get_scan_handle(TScanHandle& handle);
    //設定掃描的資料範圍
    int set_key_range(TScanHandle& handle, const K& start_key, int32_t start_exclude, const K& end_key, int32_t end_exclude);
    //讀取下一行資料
    int get_next(TScanHandle& handle, K& key, V& value);
};

支援的功能如下:

  • Put:插入一個對。
  • Get:根據key獲取對應的value。
  • Scan:掃描一段範圍內的資料行。首先,呼叫get_scan_handle獲取掃描操作描述符,其次,呼叫set_key_range設定掃描的資料範圍,最後,不斷地diao`yon呼叫get_next讀取下一行資料直到全部讀完。

為了提高讀寫併發能力,B樹實現時採用寫時複製(Copy-on-write)技術,修改每個索引節點時首先將該節點拷貝出來,接著在拷貝出來的節點上執行修改操作,最後在原子地修改其父節點的指標使其指向拷貝出來的節點。這種實現方式的好處在於修改操作不影響讀取,讀取操作永遠不會被阻塞。


相關文章