国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

跟著大彬讀源碼 - Redis 5 - 對象和數(shù)據(jù)類型(上)

antz / 2895人閱讀

摘要:對象源碼結(jié)構(gòu)如下對象類型對象編碼引用統(tǒng)計指向底層實現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針字段對象類型,就是我們常說的。。對象編碼對應(yīng)跳躍表壓縮列表集合動態(tài)字符串等八種底層數(shù)據(jù)結(jié)構(gòu)。

相信很多人應(yīng)該都知道 Redis 有五種數(shù)據(jù)類型:字符串、列表、哈希、集合和有序集合。但這五種數(shù)據(jù)類型是什么含義?Redis 的數(shù)據(jù)又是怎樣存儲的?今天我們一起來認(rèn)識下 Redis 這五種數(shù)據(jù)結(jié)構(gòu)的含義及其底層實現(xiàn)。

首先要明確的是,Redis 并沒有直接使用這五種數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)鍵值對數(shù)據(jù)庫,而是基于這些數(shù)據(jù)結(jié)構(gòu)創(chuàng)建了一套對象系統(tǒng),我們常說的數(shù)據(jù)類型,準(zhǔn)確來說,是 Redis 對象系統(tǒng)的類型。

1 對象

對于 Redis 而言,所有鍵值對的存儲,都是將數(shù)據(jù)存儲在對象結(jié)構(gòu)中。所不同的是,鍵總是一個字符串對象,值可以是任意類型的對象
對象源碼結(jié)構(gòu)如下:

typedef struct redisObject {
    unsigned type:4;       // 對象類型
    unsigned encoding:4;   // 對象編碼
    unsigned lru:LRU_BITS; // LRU
    int refcount;          // 引用統(tǒng)計
    void *ptr;             // 指向底層實現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針
} robj;

type 字段:對象類型,就是我們常說的。string、list、hash、set、zset。

encoding:對象編碼。也就是我們上面說的底層數(shù)據(jù)結(jié)構(gòu)。

LRU:鍵值對的 LRU。

refcount:鍵值對對象的引用統(tǒng)計。當(dāng)此值為 0 時,回收對象。

*ptr:指向底層實現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針。就是實際存放數(shù)據(jù)的地址。

1.2 對象類型

對象有五種數(shù)據(jù)類型,就是我們上面提過的:

字符串類型

列表類型

哈希類型

集合類型

有序集合類型

結(jié)合我們上面提到的鍵值對存儲類型的差別,可以了解到,我們常說的“一個列表鍵或一個哈希鍵”,本質(zhì)上指的是:一個 key 對應(yīng)的 value 是列表對象或哈希對象

對于 type 字段,我們可以使用 TYPE 命令來查看指定 key 對應(yīng) value 值的對象類型。

1.3 對象編碼

按道理講,已經(jīng)有了 type,為什么還要搞個編碼呢?

想想看,通過 encoding 屬性,我們是不是使用不同編碼的對象?這種使用方式可以根據(jù)不同的使用場景來為一個對象設(shè)置不同的編碼,從而優(yōu)化在某一場景下的效率,極大的提升了 Redis 的靈活性和效率。

舉個栗子,在列表對象包含的元素比較少時,Redis 使用壓縮列表作為列表對象的底層實現(xiàn):

壓縮列表比快速鏈表更節(jié)約內(nèi)存,并且在元素數(shù)量較少時,在內(nèi)存中以連續(xù)塊方式報錯的壓縮列表比起快速列表可以更快的載入到緩存中;

隨著列表對象包含的元素越來越多,使用壓縮列表保存元素的優(yōu)勢消失時,對象就會將底層實現(xiàn)從壓縮列表轉(zhuǎn)為功能更強、也更適合保存大量元素的快速鏈表。

后面介紹完編碼類型后,我們會詳細(xì)認(rèn)識不同類型對應(yīng)的各個編碼方式。

encoding 屬性有以下取值:

OBJ_ENCODING_RAW

OBJ_ENCODING_INT

OBJ_ENCODING_HT

OBJ_ENCODING_QUICKLIST

OBJ_ENCODING_ZIPLIST

OBJ_ENCODING_INTSET

OBJ_ENCODING_SKIPLIST

OBJ_ENCODING_EMBSTR

對象的編碼類型可以由 OBJECT ENCODING 命令獲取。

OBJECT ENCODING 命令對應(yīng)源碼如下:

# src/object.c
char *strEncoding(int encoding) {
    switch(encoding) {
    case OBJ_ENCODING_RAW: return "raw";
    case OBJ_ENCODING_INT: return "int";
    case OBJ_ENCODING_HT: return "hashtable";
    case OBJ_ENCODING_QUICKLIST: return "quicklist";
    case OBJ_ENCODING_ZIPLIST: return "ziplist";
    case OBJ_ENCODING_INTSET: return "intset";
    case OBJ_ENCODING_SKIPLIST: return "skiplist";
    case OBJ_ENCODING_EMBSTR: return "embstr";
    default: return "unknown";
    }
}

OBJECT ENCODING 命令輸出值與 encoding 屬性取值對應(yīng)關(guān)系如下:

對象使用的底層數(shù)據(jù)結(jié)構(gòu) 編碼常量 OBJECT ENCODING 輸出
簡單動態(tài)字符串 OBJ_ENCODING_RAW "raw"
整數(shù) OBJ_ENCODING_INT "int"
embstr 編碼的簡單動態(tài)字符串 OBJ_ENCODING_EMBSTR "embstr"
字典 OBJ_ENCODING_HT "hashtable"
壓縮列表 OBJ_ENCODING_ZIPLIST "ziplist"
快速列表 OBJ_ENCODING_QUICKLIST "quicklist"
整數(shù)集合 OBJ_ENCODING_INTSET "intset"
跳躍表 OBJ_ENCODING_SKIPLIST "skiplist"

總結(jié)來看,如下圖:

十一種不同編碼的對象分別是:

使用雙端或快速列表實現(xiàn)的列表對象

使用壓縮列表實現(xiàn)的列表對象

使用字典實現(xiàn)的哈希對象

使用壓縮列表實現(xiàn)的哈希對象

使用字典實現(xiàn)的集合對象

使用整數(shù)集合實現(xiàn)的集合對象

使用壓縮列表實現(xiàn)的有序集合對象

使用跳躍表實現(xiàn)的有序集合對象

使用普通 SDS 實現(xiàn)的字符串對象

使用 embstr 編碼的 SDS 實現(xiàn)的字符串對象

使用整數(shù)值實現(xiàn)的字符串對象

接下來,我們將對上述十一種對象一一介紹。之后再一一認(rèn)識對象編碼。

2 字符串對象

字符串對象的可選編碼分別是:int、raw 或者 embstr。

2.1 int 編碼的字符串對象

如果一個字符串對象保存的是整數(shù)值,并且這個整數(shù)值可以用 long 類型表示,那么字符串對象會將整數(shù)值保存在字符串對象結(jié)構(gòu)的 ptr 屬性中,并將字符串對象的編碼設(shè)置為 int。

我們執(zhí)行以下 SET 命令,服務(wù)器將創(chuàng)建一個如下圖所示的 int 編碼的字符串對象作為 num 鍵的值:

# redis-cli
127.0.0.1:6380> set num 12345
OK
127.0.0.1:6380> OBJECT ENCODING num
"int"

2.2 raw 編碼的字符串對象

如果字符串對象保存的是一個字符串值,并且這個字符串值的長度大于 44 字節(jié)(根據(jù)版本的不同,這個值會有差異。詳見 object.c 文件中的 OBJ_ENCODING_EMBSTR_SIZE_LIMIT 常量),那么字符串對象將使用**簡單動態(tài)字符串(SDS)來保存這個字符串值,并將對象的編碼設(shè)置為 raw。

我們執(zhí)行下面的 SET 命令,服務(wù)器將創(chuàng)建一個圖 7 所示的 raw 編碼的字符串對象作為 k1 鍵的值(45 字節(jié)):

127.0.0.1:7379> set story "k01234567890123456789012345678901234567890123"
OK
127.0.0.1:7379> OBJECT ENCODING k4
"raw"

2.3 embstr 編碼的字符串對象

如果字符串保存的是一個字符串值,并且這個字符串值的長度小于等于 44 字節(jié)(根據(jù)版本的不同,這個值會有差異。詳見 object.c 文件中的 OBJ_ENCODING_EMBSTR_SIZE_LIMIT 常量),那么字符串對象將使用 embstr 編碼的方式來保存這個字符串。

embstr 編碼是專門用于保存段字符串的一種優(yōu)化編碼方式,這種編碼和 raw 編碼一樣,都使用 redisObject 和 sdshdr 結(jié)構(gòu)來表示字符串對象。但和 raw 編碼的字符串對象不同的是:

raw 編碼會調(diào)用兩次內(nèi)存分配函數(shù)來分別創(chuàng)建 redisObject 和 sdshdr 結(jié)構(gòu)

embstr 編碼通過一次內(nèi)存分配函數(shù)分配一塊連續(xù)的空間,空間中依次包含 redisObject 和 sdsHdr 兩個結(jié)構(gòu)。

相對應(yīng)的,釋放內(nèi)存時,embstr 編碼的對象也只需調(diào)用一次內(nèi)存釋放函數(shù)。

因此,使用 embstr 編碼的字符串對象來保存短字符串值有以下好處:

創(chuàng)建字符串對象時,內(nèi)存分配次數(shù)從兩次降低為一次。

釋放 embstr 編碼的字符串對象時,調(diào)用內(nèi)存釋放函數(shù)的次數(shù)從兩次降低為一次。

更好地利用緩存優(yōu)勢。embstr 編碼的字符串對象的所有數(shù)據(jù)都保存在一塊連續(xù)的內(nèi)存中 ,這種方式比 raw 編碼的字符串對象能夠更好的利用緩存帶來的優(yōu)勢。

以下命令創(chuàng)建了一個 embstr 編碼的字符串對象作為 msg 鍵的值,值對象結(jié)構(gòu)如圖 8。

127.0.0.1:6380> SET msg hello
OK
127.0.0.1:6380> OBJECT ENCODING msg
"embstr"

2.4 浮點數(shù)編碼

Redis 中,long double 類型的浮點數(shù)也是作為字符串值來保存的。

我們要保存一個浮點數(shù)到字符串對象中,程序會先將這個浮點數(shù)轉(zhuǎn)換成字符串值,然后再保存轉(zhuǎn)換所得的字符串值。

執(zhí)行以下代碼,將創(chuàng)建一個包含 3.14 的字符串表示 "3.14" 的字符串對象:

127.0.0.1:6380> SET pi 3.14
OK
127.0.0.1:6380> OBJECT ENCODING pi
"embstr"

在有需要的時候,程序會將保存在字符串對象里的字符串值轉(zhuǎn)換成浮點數(shù)值,執(zhí)行某些操作,然后將所得的浮點數(shù)值轉(zhuǎn)換回字符串值,繼續(xù)保存在字符串對象中。

比如,我們對 pi 鍵執(zhí)行以下操作:

127.0.0.1:6380> INCRBYFLOAT pi 2.0
"5.14"
127.0.0.1:6380> OBJECT ENCODING pi
"embstr"

執(zhí)行 INCRBYFLOAT 命令過程中,實際上就會出現(xiàn)字符串與浮點數(shù)值互相轉(zhuǎn)換的情況。

2.5 編碼轉(zhuǎn)換

int 編碼的字符串對象和 embstr 編碼的字符串對象在滿足某些條件的情況下,會被轉(zhuǎn)換為 raw 編碼的字符串對象。

對于 int 編碼的字符串對象來說,如果我們在執(zhí)行命令后,使得這個對象保存的不再是整數(shù)值,而是一個字符串,那么字符串對象就會從 int 變?yōu)?raw。比如 APPEND 命令等。

另外,對于 embstr 編碼的字符串,由于 Redis 沒有為其編寫任何相應(yīng)的修改程序,所以 embstr 編碼的字符串對象實際上是只讀的。當(dāng)我們對 embstr 編碼的字符串對象執(zhí)行任何修改命令時,程序都會先將對象的編碼從 embstr 轉(zhuǎn)換成 raw。也就是說,embstr 編碼的字符串一旦修改,一定會轉(zhuǎn)換成 raw 編碼的字符串對象

2.6 值與編碼對應(yīng)關(guān)系

對于字符串對象各個編碼的情況,總結(jié)如下:

編碼
可以用 long 表示的整數(shù)值 int
可以用 long double 保存的浮點數(shù) raw 或 embstr
不可以用 long 或 long double 表示的整數(shù)或小數(shù)值 raw 或 embstr
大于 44 字節(jié)的字符串 raw
小于或等于 44 字節(jié)的字符串 embstr
3 列表對象

列表對象的可選編碼分別是:quicklist(3.2 版本前是 ziplist 和 linkedlist)。

3.1 quicklist 編碼的列表對象

3.2 版本引入了 quicklist 編碼,此編碼結(jié)合了 ziplist 和 linkedlist,使用雙向鏈表的形式,在每個節(jié)點上存儲一個 ziplist,而每個 ziplist 又可以存儲多個鍵值對。也就是說,quicklist 每個節(jié)點上存儲的不是一個數(shù)據(jù),而是一片數(shù)據(jù)。

執(zhí)行以下命令,服務(wù)器將會創(chuàng)建一個列表對象,quicklist 結(jié)構(gòu)如圖 8 所示:

127.0.0.1:7379> RPUSH animal "dog" "cat" "pig"
(integer) 3
(5.12s)
127.0.0.1:7379> OBJECT ENCODING animal
"quicklist"

總結(jié)

Redis 自己實現(xiàn)了一套對象系統(tǒng)來實現(xiàn)所有功能。

對象有對象類型對象編碼

對象類型對應(yīng)字符串、列表、哈希、集合、有序集合五種

對象編碼對應(yīng)跳躍表、壓縮列表、集合、動態(tài)字符串等八種底層數(shù)據(jù)結(jié)構(gòu)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/62139.html

相關(guān)文章

  • 跟著彬讀源碼 - Redis 6 - 對象數(shù)據(jù)類型(下)

    摘要:哈希對象哈希對象的可選編碼分別是和。編碼的哈希對象編碼的哈希對象使用壓縮列表作為底層實現(xiàn)。關(guān)于哈希編碼轉(zhuǎn)換的函數(shù),可以參考,源碼如下是原始對象,是目標(biāo)編碼。對應(yīng)源碼如下對象元素數(shù)量為,或者總結(jié)哈希對象有和編碼。 繼續(xù)擼我們的對象和數(shù)據(jù)類型。 上節(jié)我們一起認(rèn)識了字符串和列表,接下來還有哈希、集合和有序集合。 1 哈希對象 哈希對象的可選編碼分別是:ziplist 和 hashtable。...

    YFan 評論0 收藏0
  • 跟著彬讀源碼 - Redis 7 - 對象編碼之簡單動態(tài)字符串

    摘要:沒有直接使用語言傳統(tǒng)的字符串表示以空字符串結(jié)尾的字符數(shù)組,而是構(gòu)建了一種名為簡單動態(tài)字符串的抽象類型,并將用作的默認(rèn)字符串表示。對比字符串,有幾大優(yōu)點常數(shù)復(fù)雜度獲取字符串長度杜絕緩沖區(qū)溢出減少修改字符串時所需的內(nèi)存重分配次數(shù)。 Redis 沒有直接使用 C 語言傳統(tǒng)的字符串表示(以空字符串結(jié)尾的字符數(shù)組),而是構(gòu)建了一種名為簡單動態(tài)字符串(simple dynamic string)的...

    baishancloud 評論0 收藏0
  • 跟著彬讀源碼 - Redis 1 - 啟動服務(wù),程序都干了什么?

    摘要:此時服務(wù)器處于休眠狀態(tài),并使用進(jìn)行事件輪詢,等待監(jiān)聽事件的發(fā)生。繼續(xù)執(zhí)行被調(diào)試程序,直至下一個斷點或程序結(jié)束縮寫。服務(wù)啟動包括初始化基礎(chǔ)配置數(shù)據(jù)結(jié)構(gòu)對外提供服務(wù)的準(zhǔn)備工作還原數(shù)據(jù)庫執(zhí)行事件循環(huán)等。 一直很羨慕那些能讀 Redis 源碼的童鞋,也一直想自己解讀一遍,但迫于 C 大魔王的壓力,解讀日期遙遙無期。 相信很多小伙伴應(yīng)該也都對或曾對源碼感興趣,但一來覺得自己不會 C 語言,二來也...

    sewerganger 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<