Redis(五)壓縮列表介紹及部分原始碼解析

2021-09-09 07:15:12 字數 2988 閱讀 8018

壓縮列表(ziplist)是列表和雜湊物件中用於儲存資料的底層實現之一,一般用於儲存少量資料,且元素大小較小,如:較小整數,較短字串,因為壓縮列表可以使用較少的記憶體儲存多種不同型別的資料,且有著平均效能為o(n)的增刪效能。

乙個壓縮列表可以包含任意多個節點,其總體結構為:列表頭 + 資料節點 + 列表尾節點(不含資料)。

如上所述元素節點由3部分組成:前一節點長度 + 編碼方式 + 資料內容(在後面敘述)

如前所述,每個資料節點都要儲存前一節點的大小,且大小不同使用的位元組數亦不同,因此,當插入刪除節點時都可能連續更新(重新分配更大的空間)數個節點的previous_entry_length屬性。最壞情況下需要更新n個節點,而每次重新分配空間的時間複雜度為o(n),因此最壞的時間複雜度為o(n^2)。,但這僅僅發生在連續的節點大小皆為250~253位元組時(因為此時增加4個位元組後》=254位元組,從而導致了連鎖反應),這種事件的概率極低,因此幾乎不會影響效能,其平均時間複雜度為o(n)。

壓縮列表並不像其它資料結構一樣有具體的資料結構描述,其實現由一組方法的集合和一組巨集構成,如下所述:

// 定義了壓縮列表頭的大小(由兩個uint32_t和乙個uint16_t組成)

#define ziplist_header_size (sizeof(uint32_t)*2+sizeof(uint16_t))

// 定義了壓縮列表為已乙個0xff(255)表示

#define zip_end 255

// 定位到儲存壓縮列表總位元組位置

#define ziplist_bytes(zl) (*((uint32_t*)(zl)))

// 定位到儲存到壓縮列表尾偏移大小的位置

#define ziplist_tail_offset(zl) (*((uint32_t*)((zl)+sizeof(uint32_t))))

// 定位到儲存節點個數的位置

#define ziplist_length(zl) (*((uint16_t*)((zl)+sizeof(uint32_t)*2)))

// 建立乙個空的壓縮列表

unsigned char *ziplistnew(void)

//當建立完成後,空壓縮列表的結構如下所示

|<---- ziplist header ---->|<-- end -->|

大小 4 位元組 4 位元組 2 位元組 1 位元組

+---------+--------+-------+-----------+

| zlbytes | zltail | zllen | zlend |

| | | | |

value | 1011 | 1010 | 0 | 1111 1111 |

+---------+--------+-------+-----------+

// - zl  : 指向壓縮列表的首位址

// - p : 要插入的位置(插入在p之前)

// - s : 要插入元素的首位址

// - slen: 要插入元素的長度

static unsigned char *__ziplistinsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) else

}// 判斷能否將要儲存的元素轉化為整數編碼,比如字串「123456789」便可轉化為乙個整型再進行儲存

if (ziptryencoding(s,slen,&value,&encoding)) else

// 加上用於表示前一節點長度的位元組大小(1或5位元組)

reqlen += zipprevencodelength(null,prevlen);

// 加上編碼長度

reqlen += zipencodelength(null,encoding,slen);

// 此時reqlen為待插入節點的長度

// 檢查插入位置的後一節點是否足以儲存插入節點的長度資訊,nextdiff儲存了後一節點還需增大多少位元組

nextdiff = (p[0] != zip_end) ? zipprevlenbytediff(p,reqlen) : 0;

// 記錄p到壓縮列表頭的偏移,因為擴充套件壓縮列表後,壓縮列表的位址可能會發生變化。

offset = p-zl;

// 擴充套件壓縮列表,並設定了尾位元組

zl = ziplistresize(zl,curlen+reqlen+nextdiff);

// p重寫指向插入位置

p = zl+offset;

if (p[0] != zip_end)

} else

// - 若nextdiff不為0則說明插入節點後一節點變長了,

// - 因此需呼叫__ziplistcascadeupdate函式迴圈檢查後續節點,直至某個節點無需增長

if (nextdiff != 0)

/* write the entry */

p += zipprevencodelength(p,prevlen);

p += zipencodelength(p,encoding,slen);

if (zip_is_str(encoding)) else

ziplist_incr_length(zl,1);

return zl;

}// - zl : 指向壓縮列表的首位址

// - s : 要插入元素的首位元組

// - slen : 要插入元素的大小

// - where: 元素的插入位置

unsigned char *ziplistpush(unsigned char *zl, unsigned char *s, unsigned int slen, int where)

刪除元素的大致思想與插入元素相同,此處不再贅述

redis 壓縮列表

壓縮列表是列表鍵和雜湊鍵的底層實現之一。當乙個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會使用壓縮列表來做列表鍵的底層實現。另外,當乙個雜湊鍵只包含少量鍵值對,並且每個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會...

Redis之壓縮列表

壓縮列表 ziplist 是列表鍵和雜湊鍵的底層實現之一。當乙個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,redis就會使用壓縮列表來做列表鍵的底層實現。下面看一下壓縮列表實現的列表鍵 列表鍵裡面包含的都是1 3 5 10086這樣的小整數值,以及 hello...

redis筆記 壓縮列表

1.壓縮列表 壓縮列表是列表鍵和雜湊鍵的底層實現之一,當包含的少量列表項並且列表項是小整數值或者較短字串時,redis會使用壓縮列表鍵的底層實現 2.壓縮列表的構成 zlbytes 壓縮列表的總長 zltail 尾節點距離壓縮列表起始位址的便宜量 zllen 表示壓縮列表包含的節點數量 3.壓縮列表...