Redis 的設計與實現——數據結構實現之(二)鏈表與字典

鏈表      

首先Redis中存在的抽象結構爲List,而鏈表是其一種實現方式,當list元素較多或者元素都爲比較長的字符串時,採用鏈表作爲底層實現。此外,鏈表還用在Redis服務器保存客戶端狀態、發佈與訂閱功能等等。

       在Redis中,鏈表是雙向鏈表,其Node結構定義如左圖,List的定義如右圖:

觀察得知,Redis中鏈表的特點如下

  1. 無環(頭節點的pre指向null,尾節點的next也指向null)
  2. 具有頭指針和尾指針,找表頭和表尾的時間複雜度都是O(1)
  3. 雙端
  4. 多態(由於多態的存在,使得鏈表可以保存不同類型的值並正常處理)
  5. 帶有鏈表長度len

字典

       Key-value鍵值對,key獨一無二,Redis的數據庫就是用這種數據結構實現的,使用哈希表來實現,其中哈希表節點定義如左圖所示,哈希表整個的定義如右圖所示:

 

Hash節點的next指針用來鏈接同一個hash值的元素(鏈地址法解決衝突,添加到表頭O(1)

下圖是整個字典的實現,其中type用於指示鍵值對的類型,是爲了創建多態字典,Redis爲用途不同的字典配置不同的類型函數,具體如右圖所示:

 

Redis採用MurmurHash2算法來計算hash值

Rehash操作

  1. 爲hash[1]表分配空間:
    1. 如果執行擴展操作,則分配爲超過hash[0].used*2的最小2^n;
    2. 如果執行收縮操作,則分配爲超過hash[0].used的最小2^n;
  2. 將hash[0]上所有元素rehash到hash[1]上
  3. 釋放hash[0],將hash[1]置爲hash[0],在hash[1]上新建一個空白表

那麼到底啥時候進行Rehash擴容呢?

  1. 服務器目前沒在BGSAVE 或則BVGEWRITEAOF,且hash表的負載因子>=1;
  2. 服務器目前在BGSAVE 或則BVGEWRITEAOF,且hash表的負載因子>=5;
  3. 縮容是負載因子<0.1時

漸進式Hash

       在字典中維護一個rehashIdx屬性,在rehash期間,每次進行更新、刪除、查找、添加時,除了進行原有操作外,額外還將hash[0]中的rehashIdx對應的項rehash到hash[1]中去,然後將rehashIdx+1;直到所有都移動完畢,rehashIdx恢復-1。

注意,在rehash期間,所有的添加操作都在hash[1]上進行,查找、更新、刪除則要從兩個表都進行。

      

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