Redis原始碼剖析(七) 壓縮列表

2022-08-03 03:30:17 字數 2621 閱讀 9130

壓縮列表是為了節省記憶體而開發的,可以包含任意多個節點(entry),每乙個節點可以儲存乙個位元組陣列或者乙個整數值

下圖展示了壓縮列表的各個組成部分,

* 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)

previous_entry_length屬性的長度可以是1位元組或者5位元組

下圖 展示了乙個壓縮列表節點,previous_entry_length0x05, 表示前一節點的長度為5位元組。

通過previous_entry_length屬性,我們可以實現從表尾向表頭遍歷操作:

舉個例子,有乙個當前節點起始位址的指標c, 那麼我們只要用指標c減去當前節點previous_entry_length屬性的值, 就可以得出乙個指向前乙個節點起始位址的指標p

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成員負責根據encoding來儲存位元組陣列或整數

如果乙個壓縮列表中,有多個連續、長度介於250位元組到253位元組之間的節點,因此記錄這些節點只需要1個位元組的prev_entry_len,如果要插入乙個長度大於等於254的新節點到壓縮列表的頭部,然而原來的節點的prev_entry_len成員長度僅僅為1個位元組,無法儲存新節點的長度,因此會對新節點之後的所有prev_entry_len成員大小為1位元組的節點產生連鎖更新。同樣的,如果乙個壓縮列表中,是多個連續的長度大於等於254的節點,當往壓縮列表的頭部插入乙個長度小於254的節點,也會產生連鎖更新。另外刪除節點也會產生連鎖更新。

下圖展示了連鎖更新的過程:

redis原始碼剖析 skiplist

試想乙個業務場景 遊戲需要實現乙個實時更新的排行榜應該如何實現 首先想到使用有序的雙端鍊錶,因為插入的時間複雜度為o 1 但是定位的平均時間複雜度為o n 當頻繁更新排行榜的時候效率比較低 有沒有乙個結構 能夠滿足快速定位到相應的位置並插入?跳躍表就能滿足這個需求 跳躍表的思想是給資料結點建立索引 ...

redis原始碼剖析 dict

typedef struct dictentry v struct dictentry next dictentry typedef struct dicttype dicttype this is our hash table structure.every dictionary has two ...

libevent原始碼深度剖析七

事件主迴圈 張亮現在我們已經初步了解了libevent的reactor元件 event base和事件管理框架,接下來就是libevent事件處理的中心部分 事件主迴圈,根據系統提供的事件多路分發機制執行事件迴圈,對已註冊的就緒事件,呼叫註冊事件的 函式來處理事件。libevent將i o事件 定時...