Redis 的基礎資料結構(一) 可變字串、連結串列、字典

犀利豆發表於2019-02-24

原文地址:xilidou.com/2018/03/12/…

這周開始學習 Redis,看看Redis是怎麼實現的。所以會寫一系列關於 Redis的文章。這篇文章關於 Redis 的基礎資料。閱讀這篇文章你可以瞭解:

  • 動態字串(SDS)
  • 連結串列
  • 字典

三個資料結構 Redis 是怎麼實現的。

SDS

SDS (Simple Dynamic String)是 Redis 最基礎的資料結構。直譯過來就是”簡單的動態字串“。Redis 自己實現了一個動態的字串,而不是直接使用了 C 語言中的字串。

sds 的資料結構:

struct sdshdr {
    
    // buf 中已佔用空間的長度
    int len;

    // buf 中剩餘可用空間的長度
    int free;

    // 資料空間
    char buf[];
};
複製程式碼

所以一個 SDS 的就如下圖:

sds

所以我們看到,sds 包含3個引數。buf 的長度 len,buf 的剩餘長度,以及buf。

為什麼這麼設計呢?

  • 可以直接獲取字串長度。
    C 語言中,獲取字串的長度需要用指標遍歷字串,時間複雜度為 O(n),而 SDS 的長度,直接從len 獲取複雜度為 O(1)。

  • 杜絕緩衝區溢位。
    由於C 語言不記錄字串長度,如果增加一個字元傳的長度,如果沒有注意就可能溢位,覆蓋了緊挨著這個字元的資料。對於SDS 而言增加字串長度需要驗證 free的長度,如果free 不夠就會擴容整個 buf,防止溢位。

  • 減少修改字串長度時造成的記憶體再次分配。
    redis 作為高效能的記憶體資料庫,需要較高的相應速度。字串也很大概率的頻繁修改。 SDS 通過未使用空間這個引數,將字串的長度和底層buf的長度之間的額關係解除了。buf的長度也不是字串的長度。基於這個分設計 SDS 實現了空間的預分配和惰性釋放。

    1. 預分配
      如果對 SDS 修改後,如果 len 小於 1MB 那 len = 2 * len + 1byte。 這個 1 是用於儲存空位元組。
      如果 SDS 修改後 len 大於 1MB 那麼 len = 1MB + len + 1byte。
    2. 惰性釋放
      如果縮短 SDS 的字串長度,redis並不是馬上減少 SDS 所佔記憶體。只是增加 free 的長度。同時向外提供 API 。真正需要釋放的時候,才去重新縮小 SDS 所佔的記憶體
  • 二進位制安全。
    C 語言中的字串是以 ” “ 作為字串的結束標記。而 SDS 是使用 len 的長度來標記字串的結束。所以SDS 可以儲存字串之外的任意二進位制流。因為有可能有的二進位制流在流中就包含了” “造成字串提前結束。也就是說 SDS 不依賴 “

相關文章