redis數據結構底層剖析學習筆記2

四.跳躍表

跳躍表(skiplist)是一種有序數據結構,它經過在每一個節點中維持多個指向其餘節點的指針,從而達到快速訪問節點的目的。redis

redis使用跳躍表做爲有序集合的底層實現之一,若是一個有序集合包含的元素數量比較多,又或者有序集合中元素的成員是比較長的字符串時,redis就會使用跳躍表來做爲有序集合鍵的底層實現。redis只在兩個地方用到跳躍表,一個是實現有序集合鍵,另外一個是在集羣節點中用做內部數據結構。數組

4.1 跳躍表的實現

跳躍表由redis.h/zskiplistNode和redis.h/zskiplist兩個結構定義,其中zskiplistNode結構用於表示跳躍表節點,而zskiplist結構則用於保存跳躍表節點的相關信息。bash

typedef struct zskiplistNode{
	//層
	struct zskiplistLevel{
		//前進指針
		struct zskiplistNode *forward;
		//跨度
		unsigned int span;
	} level[];
	//後退指針
	struct zskiplistNode *backward;
	//分值
	double score;
	//成員對象
	robj *obj;
}zskiplistNode;

(1).層數據結構

跳躍表節點的level數組能夠包含多個元素,每一個元素都包含一個指向其餘節點的指針,程序能夠經過這些層加快訪問其餘節點的速度,通常來講,層的數量越多,訪問其餘節點的速度就越快。ui

每次建立一個新跳躍表節點的時候,程序根據冪次定律隨機生成一個介於1和32之間的值做爲level數組的大小,這個大小就是層的「高度」。編碼

(2).前進指針spa

(3).跨度3d

層的跨度用於記錄兩個節點之間的距離:指針

>兩個節點之間的跨度越大,那麼距離越遠;對象

>指向null的全部前進指針的跨度是0。

跨度是用來計算排位(rank)的。

(4).後退指針

和能夠一次跳過多個節點的前進指針不一樣,由於每一個節點只有一個後退指針,因此每次只能後退到前一個節點。

(5)分值和成員

節點的分值是一個double類型的浮點數,跳躍表的全部節點都是按分值從小倒大排序。

節點的成員對象是一個指針,它指向一個字符串對象,而字符串對象則保存着一個SDS。

在同一張跳躍表中,各個節點保存的成員必須是惟一的,可是多個節點保存的分值卻能夠是相同的:分值相同的節點將按照成員對象在字典序中的大小進行排序,小的排前面。

typedef struct zskiplist{
	//層
	struct zskiplistNode *header,*tail;
	//表中節點的數量
	unsigned long length;
	//表中層數最大的節點的層數
	int level;
}zskiplist;

 

header和tail指針分別指向跳躍表的表頭和表尾節點,經過這兩個指針,程序定位表頭節點和表尾節點的複雜度是O(1)。經過length屬性記錄節點的數量。

六.整數集合

整數集合是集合鍵的底層實現之一,當一個集合只包含整數值元素,而且這個集合的元素數量很少時,redis就會使用整數集合做爲集合鍵的底層實現。

typedef struct intset{
//編碼方式
uint32_t encoding;
//集合包含的元素數量
uint32_t length;
//保存元素的數組
int8_t contents[];
}intset;

contents數組是整數集合的底層實現:整數集合的每一個元素都是contents的一個數據項,每一個項在數組中按值的大小從小到大排列,而且數組中不包含任何重複項。

另外還有一點就是 假設一個新元素add到整數集合中,而且新元素的encoding類型比整數集合現有全部元素的類型都要長時,整數集合須要先進行升級,而後才能講新元素添加到整數集合中。一旦對數組進行了升級,沒法降級。

七.壓縮列表

壓縮列表是列表鍵和哈希鍵的底層實現之一。當一個列表鍵只包含少許列表項,而且每一個列表項要麼就是小整數值,要麼就是長度比較短的字符串,那麼redis就會使用壓縮列表做爲列表鍵的底層實現。

redis>rpush lst 1 3 5 10086 "hello" "world"
(integer) 6
redis>OBJECT ENCODING lst
"ziplist"

另外,當一個哈希鍵只包含少許鍵值對,而且每一個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字符串,那麼redis就會使用壓縮列表來作哈希鍵的底層實現。

redis>hmset profile "name" "Jack" "age" 28 "job" "teacher"
OK

redis>OBJECT ENCODING profile
"ziplist"

7.1 壓縮列表的構成

壓縮列表是redis爲了節約內存而開發的,是由一系列特殊編碼的連續內存塊組成的順序型數據結構。

一個壓縮列表能夠包含任意多個節點(entry),每一個節點能夠保存一個字節數組或者一個整數值。

 

7.2 壓縮列表節點的構成

 

 

 每一個壓縮列表節點均可以保存一個字節數組或者一個整數值。

(1)節點的previous_entry_length是以字節爲單位,記錄着前一節點的長度。經過這個屬性以及當前節點的起始值,能夠計算出上一節點的起始值。另外當前一節點的長度小於254字節,那麼previous_entry_length的長度是1字節,若是前一節點的長度大於等於254字節,那麼previous_entry_length的長度是5字節

(2)encoding記錄了節點content屬性所保存數據的長度和類型 :

>值的最高位是00,01,10的話,content保存的是字節數組;

>值的最高位是11的話,content保存的是整數。

7.3 連鎖更新

當對壓縮列表進行新增或者刪除時,可能會發生連鎖更新(由於當前一節點變成大於254字節的時候,當前節點previous_entry_length會由1字節變成5字節,假設剛好當前節點此時也變成大於254字節,那麼當前節點的下一個節點的previous_entry_length也會變化....依次進行,產生了連鎖更新)

相關文章
相關標籤/搜索