redis數(shù)據(jù)結(jié)構(gòu)之intset的實(shí)例詳解
redis數(shù)據(jù)結(jié)構(gòu)之intset的實(shí)例詳解
在redis中,intset主要用于保存整數(shù)值,由于其底層是使用數(shù)組來(lái)保存數(shù)據(jù)的,因而當(dāng)對(duì)集合進(jìn)行數(shù)據(jù)添加時(shí)需要對(duì)集合進(jìn)行擴(kuò)容和遷移操作,因而也只有在數(shù)據(jù)量不大時(shí)redis才使用該數(shù)據(jù)結(jié)構(gòu)來(lái)保存整數(shù)集合。其具體的底層數(shù)據(jù)結(jié)構(gòu)如下:
typedef struct intset {
// 編碼方式
uint32_t encoding;
// 集合包含的元素?cái)?shù)量
uint32_t length;
// 保存元素的數(shù)組
int8_t contents[];
} intset;
整數(shù)集合主要有三個(gè)屬性:encoding用于保存當(dāng)前集合的編碼,有16位,32位和64位三種;length保存了當(dāng)前整數(shù)集合中保存的數(shù)據(jù)數(shù)量;contents屬性則保存了具體的數(shù)據(jù),其每個(gè)數(shù)據(jù)占用的位數(shù)由encoding屬性指定。
這里主要需要進(jìn)行說(shuō)明的是redis的intset中數(shù)據(jù)是采用從小到大的順序存儲(chǔ)的,因而對(duì)于數(shù)據(jù)的查詢可以采用二分法進(jìn)行查詢,具體的搜索代碼如下:
static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
int64_t cur = -1;
/* The value can never be found when the set is empty */
// 處理 is 為空時(shí)的情況
if (intrev32ifbe(is->length) == 0) {
if (pos) *pos = 0;
return 0;
} else {
/* Check for the case where we know we cannot find the value,
* but do know the insert position. */
// 因?yàn)榈讓訑?shù)組是有序的,如果 value 比數(shù)組中最后一個(gè)值都要大
// 那么 value 肯定不存在于集合中,
// 并且應(yīng)該將 value 添加到底層數(shù)組的最末端
if (value > _intsetGet(is,intrev32ifbe(is->length)-1)) {
if (pos) *pos = intrev32ifbe(is->length);
return 0;
// 因?yàn)榈讓訑?shù)組是有序的,如果 value 比數(shù)組中最前一個(gè)值都要小
// 那么 value 肯定不存在于集合中,
// 并且應(yīng)該將它添加到底層數(shù)組的最前端
} else if (value < _intsetGet(is,0)) {
if (pos) *pos = 0;
return 0;
}
}
// 在有序數(shù)組中進(jìn)行二分查找
// T = O(log N)
while(max >= min) {
mid = (min+max)/2;
cur = _intsetGet(is,mid);
if (value > cur) {
min = mid+1;
} else if (value < cur) {
max = mid-1;
} else {
break;
}
}
// 檢查是否已經(jīng)找到了 value
if (value == cur) {
if (pos) *pos = mid;
return 1;
} else {
if (pos) *pos = min;
return 0;
}
}
此外,整數(shù)集合中具體還有兩個(gè)需要說(shuō)明的操作是升級(jí)和降級(jí)。升級(jí)指的是當(dāng)向低編碼的整數(shù)集合中添加位數(shù)較高的數(shù)值時(shí),就會(huì)擴(kuò)容并將整數(shù)集合中的所有元素都轉(zhuǎn)換為高位數(shù)的編碼格式,然后把新添加的元素插入到指定位置;降級(jí)指的是當(dāng)將整數(shù)集合中唯一一個(gè)高位的元素刪除時(shí)會(huì)將其余元素轉(zhuǎn)換為低位數(shù)的編碼格式,但是為了提升速率,redis中并不會(huì)為剩余元素重新分配內(nèi)存并進(jìn)行編碼轉(zhuǎn)換,而只是會(huì)將該高位元素給刪除,并重新分配內(nèi)存給剩余的元素,然后遷移數(shù)據(jù)。如圖是inset保存數(shù)據(jù)的示例:

如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
redis lua腳本實(shí)戰(zhàn)秒殺和減庫(kù)存的實(shí)現(xiàn)
本文主要是學(xué)習(xí)一下redis lua腳本的編寫,以及在redisson這個(gè)redis客戶端中是怎樣使用的,實(shí)戰(zhàn)一下秒殺場(chǎng)景redis減庫(kù)存lua腳本的編寫,并偽真實(shí)環(huán)境壓測(cè)查看效果。感興趣的可以了解一下2021-11-11
啟動(dòng)redis出現(xiàn)閃退情況的解決辦法
最近使用Redis遇到啟動(dòng)閃退的問(wèn)題,查閱資料后在一位大神的文章中找到了答案,這篇文章主要給大家介紹了關(guān)于啟動(dòng)redis出現(xiàn)閃退情況的解決辦法,需要的朋友可以參考下2023-11-11
RedisDesktopManager?連接redis的方法
這篇文章主要介紹了RedisDesktopManager?連接redis,需要的朋友可以參考下2023-08-08
redis中隊(duì)列消息實(shí)現(xiàn)應(yīng)用解耦的方法
這篇文章主要給大家介紹了關(guān)于redis中隊(duì)列消息實(shí)現(xiàn)應(yīng)用解耦的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)
這篇文章主要介紹了redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-01-01
Redis實(shí)現(xiàn)分布式事務(wù)的示例
Redis雖不支持傳統(tǒng)SQL數(shù)據(jù)庫(kù)ACID特性的事務(wù),但提供了事務(wù)特性,允許多命令捆綁執(zhí)行,通過(guò)命令MULTI、EXEC、DISCARD、WATCH實(shí)現(xiàn),感興趣的可以了解一下2024-10-10
Redis與本地緩存的結(jié)合實(shí)現(xiàn)
我們開(kāi)發(fā)中經(jīng)常用到Redis作為緩存,本文主要介紹了Redis與本地緩存的結(jié)合實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

