Redis對象——集合(Set)數據結構
以前的文章咱們曾總結到了Redis數據結構——鏈表和Redis數據結構——壓縮列表這兩種數據結構,他們是Redis List(列表)對象的底層實現方式。可是考慮到鏈表的附加空間相對過高,prev 和 next 指針就要佔去 16 個字節 (64bit 系統的指針是 8 個字節),另外每一個節點的內存都是單獨分配,會加重內存的碎片化,影響內存管理效率。所以Redis3.2版本開始對列表數據結構進行了改造,使用 quicklist 代替了 ziplist 和 linkedlist.
quicklist 其實是 zipList 和 linkedList 的混合體,它將 linkedList 按段切分,每一段使用 zipList 來緊湊存儲,多個 zipList 之間使用雙向指針串接起來。
typedef struct quicklistNode { struct quicklistNode *prev; //上一個node節點 struct quicklistNode *next; //下一個node unsigned char *zl; //保存的數據 壓縮前ziplist 壓縮後壓縮的數據 unsigned int sz; /* ziplist size in bytes */ unsigned int count : 16; /* count of items in ziplist */ unsigned int encoding : 2; /* RAW==1 or LZF==2 */ unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */ unsigned int recompress : 1; /* was this node previous compressed? */ unsigned int attempted_compress : 1; /* node can't compress; too small */ unsigned int extra : 10; /* more bits to steal for future usage */ } quicklistNode;
zlbytes
, zltail
, zllen
, zlend
和各個數據項)。須要注意的是:若是ziplist被壓縮了,那麼這個sz的值仍然是壓縮前的ziplist大小。typedef struct quicklistLZF { unsigned int sz; /* LZF size in bytes*/ char compressed[]; } quicklistLZF;
quicklistLZF結構表示一個被壓縮過的ziplist。其中:
typedef struct quicklist { quicklistNode *head; quicklistNode *tail; unsigned long count; /* total count of all entries in all ziplists */ unsigned long len; /* number of quicklistNodes */ int fill : QL_FILL_BITS; /* fill factor for individual nodes */ unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */ unsigned int bookmark_count: QL_BM_BITS; quicklistBookmark bookmarks[]; } quicklist;
list-max-ziplist-size
參數的值。list-compress-depth
參數的值。quicklist能夠選擇在頭部或者尾部進行插入(quicklistPushHead
和quicklistPushTail
),而不論是在頭部仍是尾部插入數據,都包含兩種狀況:
_quicklistNodeAllowInsert
返回1),那麼新數據被直接插入到ziplist中(調用ziplistPush
)。也能夠從任意指定的位置插入。quicklistInsertAfter
和quicklistInsertBefore
就是分別在指定位置後面和前面插入數據項。這種在任意指定位置插入數據的操做,要比在頭部和尾部的進行插入要複雜一些。
list的查找操做主要是對index的咱們的quicklist的節點是由一個一個的ziplist構成的每一個ziplist都有大小。因此咱們就只須要先根據咱們每一個node的個數,從而找到對應的ziplist,調用ziplist的index就能成功找到。
區間元素刪除的函數是 quicklistDelRange
quicklist 在區間刪除時,會先找到 start 所在的 quicklistNode,計算刪除的元素是否小於要刪除的 count,若是不知足刪除的個數,則會移動至下一個 quicklistNode 繼續刪除,依次循環直到刪除完成爲止。
quicklistDelRange 函數的返回值爲 int 類型,當返回 1 時表示成功的刪除了指定區間的元素,返回 0 時表示沒有刪除任何元素。
除了上面介紹的基本操做以外還有一些其它操做,你們能夠嘗試着根據鏈表和壓縮列表的數據結構來分析一些quicklist這些操做的時間複雜度。
操做 | 時間複雜度 |
---|---|
quicklistCreate:建立 quicklist | ? |
quicklistInsertAfter:在某個元素的後面添加數據 | ? |
quicklistInsertBefore:在某個元素的前面添加數據 | ? |
quicklistReplaceAtIndex:替換某個元素 | ? |
quicklistDelEntry:刪除單個元素 | ? |
quicklistDelRange:刪除區間元素 | ? |
quicklistPushHead:頭部插入元素 | ? |
quicklistPushTail:尾部插入元素 | ? |
Redis quicklist是Redis 3.2版本之後針對鏈表和壓縮列表進行改造的一種數據結構,是 zipList 和 linkedList 的混合體,相對於鏈表它壓縮了內存。進一步的提升了效率。
若是你有什麼疑問,歡迎在評論區給我留言和分享,我會第一時間反饋!咱們一塊兒共同窗習與進步!
《Redis設計與實現》
《Redis開發與運維》
《Redis官方文檔》
關注下方公衆號,回覆「Redis」,可得Redis相關學習資料