Redis原始碼剖析(七)--壓縮列表
阿新 • • 發佈:2018-12-24
壓縮列表的構成
壓縮列表是為了節省記憶體而開發的,可以包含任意多個節點(entry),每一個節點可以儲存一個位元組陣列或者一個整數值。
下圖展示了壓縮列表的各個組成部分,
- zlbytes:4位元組,壓縮列表所用的位元組數
- zltail:4位元組,記錄壓縮列表尾節點entryN距離壓縮列表的起始地址的位元組數。
- zllen:2位元組,壓縮列表的節點數量
- entryX:列表節點
- zlend:1位元組,特殊值
0xFF(十進位制255),
用於標記壓縮列表的末端
redis沒有使用結構體來儲存壓縮列表的資訊,而是通過巨集來定位每個成員的地址:
/* * ziplist 屬性巨集*/ // 定位到 ziplist 的 bytes 屬性,該屬性記錄了整個 ziplist 所佔用的記憶體位元組數 #define ZIPLIST_BYTES(zl) (*((uint32_t*)(zl))) // 定位到 ziplist 的 offset 屬性,該屬性記錄了到達表尾節點的偏移量 #define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint32_t)))) // 定位到 ziplist 的 length 屬性,該屬性記錄了 ziplist 包含的節點數量 #define ZIPLIST_LENGTH(zl) (*((uint16_t*)((zl)+sizeof(uint32_t)*2))) //返回 ziplist 表頭的大小 #define ZIPLIST_HEADER_SIZE (sizeof(uint32_t)*2+sizeof(uint16_t)) // 返回指向 ziplist 第一個節點(的起始位置)的指標 #define ZIPLIST_ENTRY_HEAD(zl) ((zl)+ZIPLIST_HEADER_SIZE) // 返回指向 ziplist 最後一個節點(的起始位置)的指標 #define ZIPLIST_ENTRY_TAIL(zl) ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))) // 返回指向 ziplist 末端 ZIP_END (的起始位置)的指標#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
壓縮列表節點結構
prev_entry_len成員
previous_entry_length
屬性的長度可以是 1
位元組或者 5
位元組:
- 如果前一節點的長度小於
254
位元組,previous_entry_length
的長度為1
位元組。 - 如果前一節點的長度大於等於
254
位元組,previous_entry_length
的長度為5
位元組: 其中第一位元組會被設定為0xFE
(十進位制值254
), 而之後的四個位元組則用於儲存前一節點的長度。
下圖 展示了一個壓縮列表節點,previous_entry_length
為 0x05
, 表示前一節點的長度為 5
位元組。
通過 previous_entry_length
屬性,我們可以實現從表尾向表頭遍歷操作:
舉個例子,有一個當前節點起始地址的指標 c
, 那麼我們只要用指標 c
減去當前節點 previous_entry_length
屬性的值, 就可以得出一個指向前一個節點起始地址的指標 p
。
encoding成員
redis對位元組陣列和整數編碼提供了一組巨集定義:
/* * 字串編碼型別 */ #define ZIP_STR_06B (0 << 6) #define ZIP_STR_14B (1 << 6) #define ZIP_STR_32B (2 << 6) /* * 整數編碼型別 */ #define ZIP_INT_16B (0xc0 | 0<<4) #define ZIP_INT_32B (0xc0 | 1<<4) #define ZIP_INT_64B (0xc0 | 2<<4) #define ZIP_INT_24B (0xc0 | 3<<4) #define ZIP_INT_8B 0xfe
value成員
value成員負責根據encoding來儲存位元組陣列或整數
連鎖更新
如果一個壓縮列表中,有多個連續、長度介於250位元組到253位元組之間的節點,因此記錄這些節點只需要1個位元組的prev_entry_len,如果要插入一個長度大於等於254的新節點到壓縮列表的頭部,然而原來的節點的prev_entry_len成員長度僅僅為1個位元組,無法儲存新節點的長度,因此會對新節點之後的所有prev_entry_len成員大小為1位元組的節點產生連鎖更新。同樣的,如果一個壓縮列表中,是多個連續的長度大於等於254的節點,當往壓縮列表的頭部插入一個長度小於254的節點,也會產生連鎖更新。另外刪除節點也會產生連鎖更新。
下圖展示了連鎖更新的過程: