壓縮列表 - 《Redis設計與實現》讀書筆記
阿新 • • 發佈:2021-08-02
使用場景
- 當一個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,使用壓縮列表實現列表鍵
- 當一個雜湊鍵只包含少量鍵值對,並且每個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字串,使用壓縮雜湊實現雜湊鍵
定義
// 壓縮列表是為了節約記憶體而開發出由 一系列特殊編碼的 連續記憶體塊組成的 順序型資料結構,一個壓縮列表可以包含任意多個節點 // 壓縮列表組成部分: zlbytes zltail zllen entry1 entry2 ···· entryN zlend // zlbytes : 型別為uint32_t,長度為4個位元組,記錄整個壓縮列表佔用的記憶體位元組數 // zltail : 型別為uint32_t,長度為4個位元組,記錄壓縮列表表尾節點距離壓縮列表的起始地址有多少位元組 // zllen : 型別為uint16_t,長度為2個位元組,記錄壓縮列表包含的節點數量 // entryX : 列表節點,記錄壓縮列表包含的各個節點,節點的長度由節點儲存的內容決定 // zlend : 型別為uint8_t,長度為1個位元組,特殊值0xFF(即255),用於標記壓縮列表的末端 // 壓縮列表節點:每個節點可以儲存一個字串或者一個整數值 typedef struct { // 當儲存的是位元組陣列,sval儲存字串值,slen儲存字串的長度 unsigned char *sval; unsigned int slen; // 當儲存的是整數值,lval儲存整數值,sval為NULL long long lval; // sval、lval這兩個屬性都由previous_entry_length、encoding、content三個部分組成 // previous_entry_length : 以位元組為單位,記錄前一個節點的長度,可以憑此進行指標運算,從而實現遍歷操作 // encoding : 記錄content所儲存資料的型別以及長度 // content : 儲存節點的值 } ziplistEntry;
連續更新
每個節點的previous_entry_length都記錄了前一個節點的長度:
如果前一節點的長度 < 254位元組
,那麼previous_entry_length需要用1位元組
長的空間儲存長度值
如果前一節點的長度 >= 254位元組
,那麼previous_entry_length需要用5位元組
長的空間儲存長度值
當新增新節點、刪除節點的時候,前一個節點的長度值從 小於254位元組 => 大於等於254位元組
,
從而引發
下一個節點的previous_entry_length需要從1位元組擴充套件為5位元組,
進而引發
後續節點的previous_entry_length也需要從1位元組擴充套件為5位元組,
這種特殊情況下產生的連續多次空間擴充套件操作稱之為 連鎖更新
要引發連鎖更新的機率極低
- 壓縮列表裡要
恰好有多個連續的、長度介於250位元組至253位元組之間的節點
,連鎖更新才有可能被引發,在實際中,這種情況並不多見 - 即使出現連鎖更新,但只要被更新的節點數量不多,就不會對效能造成影響,
原始碼閱讀
- 檔案:src/ziplist.h 和 src/ziplist.c