Redis底層數據結構之set


Java中的HashSet一樣,無序且存儲元素不重復。其底層有兩種實現方式,當value是整數值時,且數據量不大時使用inset來存儲,其他情況都是用字典dict來存儲。

inset

Redisinset的結構定義如下所示:

typedf struct inset{
    uint32_t encoding;//編碼方式 有三種 默認 INSET_ENC_INT16
    uint32_t length;//集合元素個數
    int8_t contents[];//實際存儲元素的數組 
                      //元素類型並不一定是ini8_t類型,柔性數組不占intset結構體大小,並且數組中的元
                      //素從小到大排列
}inset;
#define INTSET_ENC_INT16 (sizeof(int16_t))   //16位,2個字節,表示范圍-32,768~32,767
#define INTSET_ENC_INT32 (sizeof(int32_t))   //32位,4個字節,表示范
                                             //圍-2,147,483,648~2,147,483,647
#define INTSET_ENC_INT64 (sizeof(int64_t))   //64位,8個字節,表示范
//圍-9,223,372,036,854,775,808~9,223,372,036,854,775,807

編碼格式encoding:共有三種,INTSET_ENC_INT16INSET_ENC_INT32INSET_ENC_INT64三種,分別對應不同的范圍。Redis為了盡可能地節省內存,會根據插入數據的大小選擇不一樣的類型來進行存儲。

元素數量length:記錄了保存數據的數組contents中共有多少個元素,這樣獲取個數的時間復雜度就是O(1)

數組contents:真正存儲數據的地方,數組是按照從小到大有序排列的,並且不包含任何重復項

intset的示意圖如下所示:

inset中整數的升級過程

這個過程可以參考這位小姐姐寫的文章,配圖食用,效果更加。整體流程總結如下:

  • 了解舊的存儲格式,計算出目前已有元素占用內存大小,計算規則是length * encoding,如 4* 16=64;
  • 確定新的編碼格式,當原有的編碼格式不能存儲下新增的數據時,此時就要選擇新的合適的編碼格式;
  • 根據新的編碼格式計算出需要新增的內存大小,然后從尾部將數據插入;
  • 根據新的編碼格式重置之前的值,此時contents存在兩種編碼格式設置的值,就需要進行統一,從插入新數據的起始位置開始,從后向前將之前的數據按照新的編碼格式進行移動和設置。從后往前是為了防止數據被覆蓋

優點:根據存入的數據大小選擇合適的編碼方式,且只在必要的時候進行升級操作,節省內存

缺點:升級過程耗費系統資源,還有就是不支持降級,一旦升級就不可以降級

總結

參考

https://juejin.im/post/5eec5a8fe51d45742944f0f4#heading-13


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM