redis 系列8 資料結構之整數集合

2021-09-19 22:04:20 字數 3420 閱讀 2012

原文:

redis 系列8 資料結構之整數集合

一.概述

整數集合(intset)是集合鍵的底層實現之一, 當乙個集合只包含整數值元素,並且這個集合元素數量不多時, redis就會使用整數集合作為集合鍵的底層實現。下面建立乙個只包含5個元素的集合鍵,並且集合中所有元素都是整數值,那麼這個集合鍵的底層實現就會是整數集合。 接著新增非整數值,集合鍵的底層實現就會是hashtable。

127.0.0.1:6379> sadd numbers 135

79(integer)

5127.0.0.1:6379> object

encoding numbers

"intset

"127.0.0.1:6379> sadd numbers '

one'

(integer)

1127.0.0.1:6379> object

encoding numbers

"hashtable

"

二. 整數集合實現整數集合是redis用於儲存整數值的集合抽象資料結構,它可以儲存型別為int16_t, int32_t, int64_t的整數值,並且保證集合中不會出現重複元素。資料集合定義如下:

//

每個intset.h/intset結構表示乙個整數集合

typedef struct

intset

intset;

(1) contents陣列是整數集合的底層實現,整數集合的每個元素都是contents陣列的乙個陣列項(item),各個項在陣列中按值從小到大有序排列,並且陣列中不包含重複項。如下面指令碼:

127.0.0.1:6379> sadd record 534

560(integer)

5127.0.0.1:6379>smembers record

1) "0"

2) "3"

3) "4"

4) "5"

5) "

6"

(2) length屬性記錄了整數集合包含的元素數量,也即是contents陣列的長度。雖然contents屬性宣告為int8_t型別的陣列,但實現上contents陣列並不儲存任何int8_t型別的值,contents陣列的真正型別取決於encoding屬性的值。

a. 如果encoding 屬性的值為intset_enc_int16,那麼contents就是乙個int16_t型別的陣列,陣列裡的每個項都是乙個int16_t型別的整數值(範圍在 -32768 ~ 32767)。如下圖encoding屬性的值有5個整數型,根據這些整數值得出encoding為int16_t型別。

b. 如果encoding屬性的值為intset_enc_int32, 那麼陣列裡每個項就是乙個int32_t型別的整數值(範圍在 -2147483648 ~ 2147483647)。還有encoding屬性的值為intset_enc_int64型別的,陣列裡每個項取取值範圍更大。

需要注意的是:假設contents陣列儲存的值為2147483647, 1,2,3 四個整數值。 但只有第乙個整數值需要用int32_t型別來儲存,而其它三個值可以用int16_t型別來儲存。不過根據整數集合的公升級規則,當乙個底層的int16_t陣列的整數集合新增乙個int64_t型別的整數值時,整數集合中所有元素都會被轉換成int64_t型別。 所以contents陣列儲存的整數值都是int64_t型別的。

三. 公升級

當我們要將乙個新元素新增到整數集合裡面,並且新元素的型別比整數集合現有所有元素的型別都要長時,整數集合需要先進行公升級,然後才能將新元素新增到整數集合中。假設:集合中包含三個int16_t型別的元素,值分別是1,2,3 。因為每個元素都占用16位空間,所以整數集合底層陣列的大小 為3 * 16 =48位。現將int32_t的數值65535新增進去,這裡程式需要對整數集合進行公升級。

公升級整數集合並新增新元素共分三步進行:

(1) 根據新元素的型別,擴充套件整數集合底層陣列的空間大小 ,並為新元素分配空間。分配空間後,現在整數集合4個元素的底層陣列大小為4 *32 =128位, 此時前三位還是48位空間,如下圖所示:

(2) 將底層陣列現有的所有元素都轉換成與新元素相同的型別(需要從int16_t 轉成int32_t所需的空間) ,轉換後元素位置有序不變,如下圖所示:

(3) 將新元素新增到底層陣列裡面,如下圖所示:

四. 公升級的好處

4.1 提公升靈活性

為了避免型別錯誤,通常不會將兩種不同型別的值放在同乙個資料結構裡面,通過公升級處理可以隨意地將int16_t, int32_t, , int64_t 型別的整數新增到集合中,而不必擔心出現型別錯誤。

4.2 節約記憶體

要讓乙個陣列可以同時儲存int16_t,int32_t, , int64_t三種型別的值,最簡單的做法就是直接使用int64_t型別的陣列作為整數集合的底層實現,不過這樣浪費記憶體空間。

五.   降級

整數集合不支援降級操作,一旦對陣列進行了公升級,編碼就會一直保持公升級後的狀態。即使集合裡只有乙個需要使用int64_t型別的元素被刪除了,整數集合的編碼仍然會維持intset_enc_int64, 底層陣列也仍然會是int64_t型別,如下圖所示:

六. 整數集合api

函式

作用

intsetnew

建立乙個新的壓縮列表

intsetadd

將給定元素新增到整數集合裡面

intsetremove

從整數集合中移除給定元素

intsetfind

檢查給定值是否存在於集合

intsetrandom

從整數集合中隨機返回乙個元素

intsetget

取出底層陣列在給定索引上的元素

intsetlen

返回整數集合包含的元素個數

intsetbloblen

返回整數集合占用的記憶體位元組數

Redis資料結構 整數集合

最新 redis記憶體 三個重要的緩衝區 最新 redis記憶體 記憶體消耗 記憶體都去哪了?最新 redis持久化 如何選擇合適的持久化方式 最新 redis持久化 aof日誌 整數集合 intset 並不是乙個基礎的資料結構,而是redis自己設計的一種儲存結構,是集合鍵的底層實現之一,當乙個集...

Redis資料結構 intset(整數集合)

整數集合是redis集合鍵的底層實現之一,如果乙個集合只包含整數值元素,而且元素數量不多,redis就會用整數集合作為集合鍵的底層實現 redis集合鍵的另一種底層實現是跳表 一 整數集合的應用場景 跟整數集合intset相關的redis命令主要有zadd sadd等等 二 整數集合的資料結構 ty...

Redis資料結構 整數集合 intset

整數集合 整數集合是集合鍵的底層實現之一,當乙個集合只包含整數值元素,並且這個集合的元素數量不多時,redis就會使用整數集合作為集合鍵的底層實現。1 整數集合實現 整數集合是redis用於儲存整數值的集合抽象資料結構,它可以可以儲存型別位int16 t int32 t int64 t的整數值,並且...