redis 整數集合、壓縮列表和對象

整數集合

整數集合(intset)是redis用於保存整數值的集合抽象數據結構,它可以保存類型爲int16_t、int32_t、int64_t的整數值,並且保證集合中不會出現重複元素。

數據結構:

typedef struct intset {
    uint32_t encoding;//INTSET_ENC_INT16、INTSET_ENC_INT32、INTSET_ENC_INT64
    uint32_t length;	 //記錄數組包含元素數量
    int8_t contents[];
} intset;

contents數組是整個集合的底層實現:整數集合的每個元素都是contents數組的一個數組項(item), 各個項在數組中按值的大小從小到大有序排列。、

升級:

content保存着原來數組,如果添加進來一個數據長度要大於之前數組長度,就會升級

升級步驟:

1 根據新元素類型,擴展整數集合底層數組的空間大小,併爲新元素分配空間

2 將底層數組現有的所有元素都轉換成與新元素相同的類型,並將類型轉換後的元素放置在正確的位置上,而且在放置元素的過程中,需要繼續維持底層數組的有序性質不變

3 將新元素添加到底層數組裏面

//升級函數

static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
    uint8_t curenc = intrev32ifbe(is->encoding);
    uint8_t newenc = _intsetValueEncoding(value);
    int length = intrev32ifbe(is->length);
    int prepend = value < 0 ? 1 : 0;

    /* First set new encoding and resize */
    is->encoding = intrev32ifbe(newenc);
    is = intsetResize(is,intrev32ifbe(is->length)+1);

    /* Upgrade back-to-front so we don't overwrite values.
     * Note that the "prepend" variable is used to make sure we have an empty
     * space at either the beginning or the end of the intset. */
    while(length--)
        _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));

    /* Set the value at the beginning or the end. */
    if (prepend)
        _intsetSet(is,0,value);
    else
        _intsetSet(is,intrev32ifbe(is->length),value);
    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
    return is;
}
//添加
intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
    uint8_t valenc = _intsetValueEncoding(value);
    uint32_t pos;
    if (success) *success = 1;

    /* Upgrade encoding if necessary. If we need to upgrade, we know that
     * this value should be either appended (if > 0) or prepended (if < 0),
     * because it lies outside the range of existing values. */
    if (valenc > intrev32ifbe(is->encoding)) {
        /* This always succeeds, so we don't need to curry *success. */
//編碼大於之前,需要升級
        return intsetUpgradeAndAdd(is,value);
    } else {
        /* Abort if the value is already present in the set.
         * This call will populate "pos" with the right position to insert
         * the value when it cannot be found. */
//找到最佳位置
        if (intsetSearch(is,value,&pos)) {
            if (success) *success = 0;
            return is;
        }
//擴展大小
        is = intsetResize(is,intrev32ifbe(is->length)+1);
//move
        if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
    }
//set
    _intsetSet(is,pos,value);
    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
    return is;
}

壓縮列表

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

長度/類型

域的值

zlbytes

uint32_t

整個 ziplist 佔用的內存字節數,對 ziplist 進行內存重分配,或者計算末端時使用。

zltail

uint32_t

到達 ziplist 表尾節點的偏移量。 通過這個偏移量,可以在不遍歷整個 ziplist 的前提下,彈出表尾節點。

zllen

uint16_t

ziplist 中節點的數量。 當這個值小於 UINT16_MAX (65535)時,這個值就是 ziplist 中節點的數量; 當這個值等於 UINT16_MAX 時,節點的數量需要遍歷整個 ziplist 才能計算得出。

entryX

?

ziplist 所保存的節點,各個節點的長度根據內容而定。

zlend

uint8_t

255 的二進制值 1111 1111 (UINT8_MAX) ,用於標記 ziplist 的末端。

對象

redis並沒有直接使用這些原始的數據結構,而是把這些數據結構封裝成對象。這個系統包含字符串對象、列表對象、哈希對象、集合對象、有序集合對象, 這些對象會根據不同場景使用不同數據結構

typedef struct redisObject {
    unsigned type:4;				//對象類型
    unsigned encoding:4;			//對象使用編碼
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;					//指向對象的底層數據結構
} robj;

類型:

對象

對象type屬性的值

type命令的輸出

字符串對象

REDIS_STRING

“string”’

列表對象

REDIS_LIST

“list”

哈希對象

REDIS_HASH

“hash”

集合對象

REDIS_SET

“set”

有序集合對象

REDIS_HSET

“zset”

編碼:

編碼常量

底層數據結構

 

REDIS_ENCODING_INT

long類型的整數

REDIS_STRING

REDIS_ENCODING_EMBSTR

embstr編碼的簡單動態字符串

REDIS_ENCODING_RAW

簡單動態字符串

REDIS_ENCODING_HT

字典

REDIS_HASH

REDIS_SET

REDIS_ENCODING_LINKEDLIST

雙端鏈表

REDIS_LIST

REDIS_ENCODING_ZIPLIST

壓縮列表

REDIS_LIST

REDIS_HASH

REDIS_ZSET

REDIS_ENCODING_INTSET

整數集合

REDIS_SET

REDIS_ENCODING_SKIPLIST

跳躍表和字典

REDIS_ZSET

對redis數據庫保存的鍵值對來說,鍵總是一個字符串對象,而值可以是字符串對象、列表對象、哈希對象、集合對象、有序集合對象的其中一種。

 

通過encoding屬性來設定對象所使用的編碼,而不是爲特定類型的對象關聯一種固定的編碼,極大的提升了redis的靈活性和效率。

 

有序集合zset 是dict和skiplist結合 dict保存key->score skiplist保存zset 數據

發佈了83 篇原創文章 · 獲贊 8 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章