溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

redis整數(shù)集為什么不能降級(jí)

發(fā)布時(shí)間:2021-07-21 16:38:58 來源:億速云 閱讀:118 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“redis整數(shù)集為什么不能降級(jí)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“redis整數(shù)集為什么不能降級(jí)”吧!

目錄
  • 前言

  • 基本結(jié)構(gòu)

  • 何時(shí)使用intset

  • intset

  • 添加元素

  • 類型變動(dòng)

  • 升級(jí)

  • 加入65535

  • 舊數(shù)據(jù)移位

  • 降級(jí)

  • 為什么不實(shí)現(xiàn)降級(jí)


前言

整數(shù)集合相信有的同學(xué)沒有聽說過,因?yàn)閞edis對外提供的只有封裝的五大對象!而我們本系列主旨是學(xué)習(xí)redis內(nèi)部結(jié)構(gòu)。內(nèi)部結(jié)構(gòu)是redis五大結(jié)構(gòu)重要支撐!

前面我們分別從redis內(nèi)部結(jié)構(gòu)分析了redis的List、Hash、Zset三種數(shù)據(jù)結(jié)構(gòu)了。今天我們再來分析set數(shù)據(jù)結(jié)構(gòu)內(nèi)部是如何存儲(chǔ)的

基本結(jié)構(gòu)

在src/t_set.c中我們發(fā)現(xiàn)這樣一段代碼

redis整數(shù)集為什么不能降級(jí)

由此我們可知在set中是由兩種數(shù)據(jù)結(jié)構(gòu)構(gòu)成的: hashtable+intset 。關(guān)于redis內(nèi)部其他的結(jié)構(gòu)我專門在【redis專欄中有介紹】。hashtable不是我們今天的主角,我們今天先分析intset俗稱整數(shù)集合。

redis整數(shù)集為什么不能降級(jí)

從上圖中我們可以看出,我構(gòu)造了兩個(gè)set集合分別為【commonset】、【cs】。兩個(gè)集合前者存儲(chǔ)字符串、后者專門存儲(chǔ)數(shù)字。

我們在通過object encoding key 來查看下兩個(gè)集合的底層數(shù)據(jù)結(jié)構(gòu),發(fā)現(xiàn)一個(gè)是hashtable 一個(gè)是intset 。這也驗(yàn)證了我們上面對set基本結(jié)構(gòu)的描述。

在redis中對外提供五大類型實(shí)際上都是redis的一個(gè)抽象對象叫做redisobject。在內(nèi)部映射了我們r(jià)edis內(nèi)部的數(shù)據(jù)結(jié)構(gòu)

redis整數(shù)集為什么不能降級(jí)

針對commonset和cs兩個(gè)集合在內(nèi)部數(shù)據(jù)結(jié)構(gòu)大概可以這么理解

redis整數(shù)集為什么不能降級(jí)

何時(shí)使用intset

你可以單純的認(rèn)為只要是數(shù)字就會(huì)使用intset結(jié)構(gòu)來存儲(chǔ),我恐怕要給你當(dāng)頭一棒了。實(shí)際上并不是這樣

需要同時(shí)滿足以下兩個(gè)條件:

redis整數(shù)集為什么不能降級(jí)

redis整數(shù)集為什么不能降級(jí)

intset

redis整數(shù)集為什么不能降級(jí)

圖中表示的很清楚了,在intset中的encoding有三種取值分別代表contents保存數(shù)據(jù)類型。這里有人可能會(huì)有疑問了contents的類型不就是int8_t嗎?為什么還需要encoding呢?這里通過源碼跟蹤內(nèi)部的確跟int8_t沒啥關(guān)系。而且數(shù)據(jù)的默認(rèn)類型就是int16_t 。關(guān)于length這里無需太多解釋,記住一點(diǎn)表示contents元素的個(gè)數(shù)并非表示contents數(shù)組的長度!

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

int8_t的取值范圍是【-128,127】 。 類似于java中byte占1個(gè)字節(jié)也就是8位。他的取值范圍是

redis整數(shù)集為什么不能降級(jí)

redis整數(shù)集為什么不能降級(jí)

添加元素

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

juejin這個(gè)key內(nèi)部就是intset 。

redis整數(shù)集為什么不能降級(jí)

上面我們添加了5個(gè)元素且這五個(gè)元素的長度都在16之內(nèi)!所以當(dāng)前的intset的encoding=INTSET_ENC_INT16。-123在contents中占前16位。

所以當(dāng)前五個(gè)元素占contents的長度是16*5=80 ;

注意set在存儲(chǔ)int類型數(shù)據(jù)時(shí),內(nèi)部是按照從小到大的順序存儲(chǔ)的。

類型變動(dòng)

redis整數(shù)集為什么不能降級(jí)

上面的問題不知道你有沒有考慮過,或者說有沒有遇到過!intset默認(rèn)是int16位,正如我們上面添加的五個(gè)元素。加入此時(shí)我們添加第6個(gè)元素是65535(32位)。那么此時(shí)16位的長度就不夠存儲(chǔ)了這個(gè)時(shí)候intset會(huì)怎么做!

另外當(dāng)我們添加第6個(gè)元素后又將65535刪除了之后,結(jié)構(gòu)和添加之前是否一樣!下面我們帶著這兩個(gè)問題來一探究竟?。?!

升級(jí)

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

答案是肯定不行,首先直接追加無法保證數(shù)組元素的大小順序!其次如果前五個(gè)分別是16位,第6個(gè)是32位那么在intset結(jié)構(gòu)中沒有多余的字段來進(jìn)行標(biāo)記。也就是說在解析的時(shí)候就無法判斷應(yīng)該解析16位還是32位了.

redis為了方便解析所以在有高長度加入時(shí)會(huì)將整個(gè)contents進(jìn)行升級(jí)。意思就是將整個(gè)contents先進(jìn)行擴(kuò)容,然后在重新填充數(shù)據(jù)

redis整數(shù)集為什么不能降級(jí)

加入65535

首先根據(jù)length可以確定擴(kuò)容后元素個(gè)數(shù)為6 , 每個(gè)占位32,所以contents長度為32*6=192 。 此時(shí)前80位內(nèi)容保持不變

redis整數(shù)集為什么不能降級(jí)

舊數(shù)據(jù)移位

開辟了足夠的空間后,我們就可以對舊數(shù)據(jù)進(jìn)行移位了這里我們從原數(shù)組的末尾開始移動(dòng),在移動(dòng)之前需要明確在新數(shù)組中的排序位置。此時(shí)我們首先將321進(jìn)行比對確定在新數(shù)組中他的排名是第五名,那么他將占用新contents中128~159區(qū)間。

redis整數(shù)集為什么不能降級(jí)

最終前5 個(gè)元素就會(huì)被移動(dòng)好 。

redis整數(shù)集為什么不能降級(jí)

最后將新加入的元素填充進(jìn)去。當(dāng)發(fā)生升級(jí)時(shí)肯定是因?yàn)樾略氐拈L度大于原有長度了。那么他的值一定會(huì)是在新數(shù)組的兩端。負(fù)數(shù)在最左側(cè),正數(shù)在最右側(cè)

redis整數(shù)集為什么不能降級(jí)

降級(jí)

接下來就是第二個(gè)問題當(dāng)新加入的65535又被刪除了redis該怎么辦,這個(gè)時(shí)候元素長度實(shí)際16位就可以滿足了,但是此時(shí)encoding卻是32位的。按照我的看法應(yīng)該在實(shí)現(xiàn)降級(jí)!

但是遺憾的是redis并沒有,那么請思考為什么沒有?如果讓你實(shí)現(xiàn)你將如何實(shí)現(xiàn)

為什么不實(shí)現(xiàn)降級(jí)

當(dāng)加入元素超過當(dāng)前長度我們很容易就知道此時(shí)需要進(jìn)行升級(jí)操作,但是當(dāng)我們刪除一個(gè)數(shù)據(jù)時(shí)我們?nèi)绾闻袛嗍欠裥枰导?jí)卻很困難,我們需要重新遍歷一遍剩下的元素是否小于當(dāng)前長度,實(shí)現(xiàn)復(fù)雜度O(N) 。這就是為什么不進(jìn)行降級(jí)原因之一

你可能會(huì)說重新遍歷一遍很快的反正在內(nèi)存中,那么你有沒有想過如果降級(jí)之后又遇到升級(jí)情況,這樣來回的升級(jí)降級(jí)就降低了我們程序的性能了。我們知道升級(jí)是必須的所以這里降級(jí)redis采取的是忽略的策略

到此,相信大家對“redis整數(shù)集為什么不能降級(jí)”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI