首頁 >資料庫 >Redis >redis整數集不能降級?為什麼?

redis整數集不能降級?為什麼?

醉折花枝作酒筹
醉折花枝作酒筹轉載
2021-07-28 17:46:472281瀏覽

整數集合相信有的同學沒有聽過,因為redis對外提供的只有封裝的五大物件!前面我們分別從redis內部結構分析了redis的List、Hash、Zset三種資料結構了。今天我們再來分析set資料結構內部是如何儲存的。

基本結構

在src/t_set.c中我們發現這樣一段程式碼

redis整數集不能降級?為什麼?

由此我們可知在set中是由兩種資料結構構成的: hashtable intset 。關於redis內部其他的結構我專門在【redis專欄中有介紹】。 hashtable不是我們今天的主角,我們今天先分析intset俗稱整數集合。

redis整數集不能降級?為什麼?

從上圖我們可以看出,我建構了兩個set集合分別為【commonset】、【cs】。兩個集合前者儲存字串、後者專門儲存數字。

我們透過object encoding key 查看下兩個集合的底層資料結構,發現一個是hashtable 一個是intset  。這也驗證了我們上面對set基本結構的描述。

在redis中對外提供五大型別其實都是redis的一個抽象物件叫做redisobject。在內部映射了我們redis內部的資料結構

redis整數集不能降級?為什麼?

針對commonset和cs兩個集合在內部資料結構大概可以這麼理解

redis整數集不能降級?為什麼?

何時使用intset

你可以單純的認為只要是數字就會使用intset結構來存儲,我恐怕要給你當頭一棒了。其實並不是這樣

需要同時滿足以下兩個條件:

redis整數集不能降級?為什麼?

redis整數集不能降級?為什麼?

intset

redis整數集不能降級?為什麼?

##圖中表示的很清楚了,在intset中的encoding有三種取值分別代表contents保存資料型別。這裡有人可能會有疑問了contents的型別不就是int8_t嗎?為什麼還需要encoding呢?這裡透過原始碼追蹤內部的確跟int8_t沒啥關係。而且資料的預設型別就是int16_t 。關於length這裡不需要太多解釋,記住一點表示contents元素的數量並非表示contents陣列的長度!

了解intset的同學都知道在encoding三種取值範圍中涉及了升級的操作!在講升級之前我們先來了解下C、C 中int的取值範圍是如何定義的

int8_t的取值範圍是【-128,127】 。類似java中byte佔1個位元組也就是8位元。他的值範圍是\[-2^{7} \sim 2^{7}-1   \\#即

\\ -128 \sim 127 \]

redis整數集不能降級?為什麼?

新增元素

sadd juejin -123
sadd juejin -6
sadd juejin 12
sadd juejin 56
sadd juejin 321

juejin這個key內部就是intset 。 redis整數集不能降級?為什麼?

上面我們加入了5個元素且這五個元素的長度都在16之內!所以目前的intset的encoding=INTSET_ENC_INT16。 -123在contents中佔前16位。

所以目前五個元素佔contents的長度是16*5=80 ;

注意set在儲存int型別資料時,內部是依照從小到大的順序儲存的。

型別變動redis整數集不能降級?為什麼?

上面的問題不知道你有沒有考慮過,或是有沒有遇過! intset預設是int16位,正如我們上面添加的五個元素。加入此時我們加入第6個元素是65535(32位元)。那麼此時16位元的長度就不夠儲存了這時候intset會怎麼做!

另外當我們加入第6個元素後又將65535刪除了之後,結構和新增之前是否一樣!下面我們就帶著這兩個問題來一探究竟! ! !

升級

###首先我們針對第一問題來看。原來五個元素都是16位元就可以滿足了,這時候增加的65535是32位元長度的。那麼是不是可以直接追加32位元分配給65535呢? ###

答案是肯定不行,首先直接追加無法保證陣列元素的大小順序!其次如果前五個分別是16位,第6個是32位那麼在intset結構中沒有多餘的字段來進行標記。也就是說在解析的時候就無法判斷應該解析16位元還是32位元了.

redis為了方便解析所以在有高長度加入時會將整個contents進行升級。意思就是將整個contents先擴容,然後在重新填入資料

redis整數集不能降級?為什麼?

加入65535

先根據length可以決定擴容後元素個數為6 , 每個佔位32,所以contents長度為32*6=192 。此時前80位元內容保持不變

redis整數集不能降級?為什麼?

舊資料移位

開闢了足夠的空間後,我們就可以對舊資料進行移位了這裡我們從原始數組的末尾開始移動,在移動之前需要明確在新數組中的排序位置。

此時我們首先將321進行比對確定在新數組中他的排名是第五名,那麼他將佔用新contents中128~159區間。

redis整數集不能降級?為什麼?

最終前5 個元素就會被移動好 。

redis整數集不能降級?為什麼?

最後將新加入的元素填入。當發生升級時肯定是因為新元素的長度大於原有長度了。那麼他的值一定會是在新數組的兩端。負數在最左側,正數在最右側

redis整數集不能降級?為什麼?

降級

接下來就是第二個問題當新加入的65535又被刪除了redis該怎麼辦,這時候元素長度實際16位就可以滿足了,但是此時encoding卻是32位的。按照我的看法應該在實現降級!

但遺憾的是redis並沒有,那請思考為什麼沒有?如果讓你實現你將如何實現

為什麼不實現降級

當加入元素超過當前長度我們很容易就知道此時需要進行升級操作,但是當我們刪除一個資料時我們如何判斷是否需要降級卻很困難,我們需要重新遍歷一遍剩下的元素是否小於目前長度,而實現複雜度O(N) 。這就是為什麼不進行降級原因之一

你可能會說重新遍歷一遍很快的反正在內存中,那麼你有沒有想過如果降級之後又遇到升級情況,這樣來回的升級降級就降低了我們程式的效能了。我們知道升級是必須的所以這裡降級redis採取的是忽略的策略

小結

redis整數集不能降級?為什麼?

#相關教程推薦:Redis教程

以上是redis整數集不能降級?為什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除