string類型的數(shù)據(jù)結(jié)構(gòu)SDS到底是什么東西

基本介紹

String 是最基本的 key-value 結(jié)構(gòu),key 是唯一標(biāo)識,value 是具體的值,value其實(shí)不僅是字符串, 也可以是數(shù)字(整數(shù)或浮點(diǎn)數(shù))以及二進(jìn)制等,value 最多可以容納的數(shù)據(jù)長度是 512M。

本文主要介紹的就是String類型中的SDS(Simple Dynamic String),俗稱簡單動態(tài)字符串。

內(nèi)部實(shí)現(xiàn)

要知道在redis中的String、map、list、set、zset類型都有各自的結(jié)構(gòu)體。

list類型的結(jié)構(gòu)體如下:

class RedisListObject {
    int type;          // 數(shù)據(jù)類型標(biāo)識
    int encoding;      // 編碼方式標(biāo)識
    int refcount;      // 引用計(jì)數(shù)
    int length;        // 列表長度
    RedisListNode head; // 列表頭節(jié)點(diǎn)指針
    RedisListNode tail; // 列表尾節(jié)點(diǎn)指針
}

class RedisListNode {
    RedisListObject obj; // 列表節(jié)點(diǎn)的值,可以是字符串對象等
    RedisListNode prev;  // 前一個(gè)節(jié)點(diǎn)指針
    RedisListNode next;  // 后一個(gè)節(jié)點(diǎn)指針
}

map類型的結(jié)構(gòu)體如下:

class RedisHashObject {
    int type;              // 數(shù)據(jù)類型標(biāo)識
    int encoding;          // 編碼方式標(biāo)識
    int refcount;          // 引用計(jì)數(shù)
    int length;            // 哈希表中鍵值對的數(shù)量
    RedisHashEntry[] table; // 哈希表數(shù)組,每個(gè)元素是一個(gè)鍵值對
}

class RedisHashEntry {
    RedisObject key;       // 鍵對象
    RedisObject value;     // 值對象
    RedisHashEntry next;   // 指向下一個(gè)哈希表節(jié)點(diǎn)的指針
}

set類型的結(jié)構(gòu)體如下:

class RedisSetObject {
    int type;              // 數(shù)據(jù)類型標(biāo)識
    int encoding;          // 編碼方式標(biāo)識
    int refcount;          // 引用計(jì)數(shù)
    int length;            // 集合中元素的數(shù)量
    RedisSetNode[] table;  // 集合節(jié)點(diǎn)數(shù)組
}

class RedisSetNode {
    RedisObject value;     // 集合節(jié)點(diǎn)的值
    RedisSetNode next;     // 指向下一個(gè)集合節(jié)點(diǎn)的指針
}

String類型的結(jié)構(gòu)體如下:

typedef struct redisObject {
    unsigned type;          // 類型標(biāo)識,用于表示對象的類型,如字符串、列表等
    unsigned encoding;      // 編碼標(biāo)識,用于表示對象的編碼方式,如 RAW、EMBSTR 等
    int refcount;           // 引用計(jì)數(shù),記錄對象被引用的次數(shù)
    void *ptr;              // 指向底層實(shí)際數(shù)據(jù)的指針
}

可以發(fā)現(xiàn)每種結(jié)構(gòu)體都有3個(gè)共同的屬性即typeencodingrefcount

本文我們主要討論的是String類型的存儲結(jié)構(gòu),而對于String類型來說,encoding編碼格式有3種,即intembstrrow,不同的編碼格式對應(yīng)的字符串的存儲類型也是不同的。

編碼為int

如果一個(gè)字符串對象保存的是整數(shù)值,并且這個(gè)整數(shù)值可以用long類型來表示時(shí):

  • 字符串結(jié)構(gòu)體中的encoding設(shè)置為int
  • 字符串結(jié)構(gòu)體中ptr屬性轉(zhuǎn)化為long類型,且直接存儲對應(yīng)整形value值。
typedef struct redisObject {
    unsigned type;          // 類型標(biāo)識:這里為字符串
    unsigned encoding;      // 編碼標(biāo)識:int
    int refcount;           // 引用計(jì)數(shù),記錄對象被引用的次數(shù)
    long ptr;              // 直接存儲對應(yīng)的整形值,比如132132
}

編碼為embstr

如果字符串對象保存的是一個(gè)字符串,并且這個(gè)字符申的長度小于等于 32 字節(jié)(redis 2.+版本)時(shí):

  • 字符串結(jié)構(gòu)體中的encoding設(shè)置為embstr
  • 字符串結(jié)構(gòu)體中ptr屬性轉(zhuǎn)化為char []字符數(shù)組類型,且直接存儲對應(yīng)的字符串。
typedef struct redisObject {
    unsigned type;          // 類型標(biāo)識:這里為字符串
    unsigned encoding;      // 編碼標(biāo)識:embstr
    int refcount;           // 引用計(jì)數(shù),記錄對象被引用的次數(shù)
    char[] ptr;              // 直接存儲對應(yīng)的整形值,比如['a','b','c']
}

編碼為row

如果字符串對象保存的是一個(gè)字符串,并且這個(gè)字符串的長度大于 32 字節(jié)(redis 2.+版本)時(shí):

  • 字符串結(jié)構(gòu)體中的encoding設(shè)置為row
  • 字符串結(jié)構(gòu)體中ptr將指向一個(gè)SDS結(jié)構(gòu)體,該結(jié)構(gòu)體如下:
struct sdshdr {
    unsigned int len;       // 已使用的字節(jié)數(shù)
    unsigned int free;      // 剩余的字節(jié)數(shù)
    char buf[];             // 字符數(shù)組,用于存儲字符串?dāng)?shù)據(jù)
};
  • len: 記錄當(dāng)前字符串的長度,表示 buf 數(shù)組中已使用的字節(jié)數(shù)。這個(gè)值可以直接獲取,使得獲取字符串長度的操作具有 O(1) 復(fù)雜度。
  • free: 記錄 buf 數(shù)組中未使用的字節(jié)數(shù),即空余空間的大小。當(dāng)執(zhí)行字符串追加操作(例如 APPEND)時(shí),如果追加的內(nèi)容長度大于 free 的大小,SDS 會自動擴(kuò)展 buf 的大小,確保足夠的空間容納新的內(nèi)容,避免緩沖區(qū)溢出。
  • buf(buffer): 用于存儲字符串內(nèi)容的字符數(shù)組

此時(shí)的String類型的結(jié)構(gòu)體如下:

typedef struct redisObject {
    unsigned type;          // 類型標(biāo)識:這里為字符串
    unsigned encoding;      // 編碼標(biāo)識:row
    int refcount;           // 引用計(jì)數(shù),記錄對象被引用的次數(shù)
    sdshdr *ptr;              // 指向一個(gè)SDS結(jié)構(gòu)體,該結(jié)構(gòu)體存儲存儲對應(yīng)的字符串信息
}

總結(jié)

SDS 和我們認(rèn)識的 C 字符串不太一樣,之所以沒有使用 C 語言的字符串表示,因?yàn)?SDS 相比于 C 的原生字符串:

  • SDS 不僅可以保存文本數(shù)據(jù),還可以保存二進(jìn)制數(shù)據(jù)。因?yàn)?SDS 使用 len 屬性的值而不是空字符來判斷字符串是否結(jié)束,并且 SDS 的所有 API 都會以處理二進(jìn)制的方式來處理 SDS 存放在 buf[] 數(shù)組里的數(shù)據(jù)。所以 SDS 不光能存放文本數(shù)據(jù),而且能保存圖片、音頻、視頻、壓縮文件這樣的二進(jìn)制數(shù)據(jù)。
  • SDS 獲取字符串長度的時(shí)間復(fù)雜度是O(1)。因?yàn)?C 語言的字符串并不記錄自身長度,所以獲取長度的復(fù)雜度為 O(n);而 SDS 結(jié)構(gòu)里用 len 屬性記錄了字符串長度,所以復(fù)雜度為 O(1)。
  • Redis 的 SDS API 是安全的,拼接字符串不會造成緩沖區(qū)溢出。因?yàn)?SDS 在拼接字符串之前會檢查 SDS 空間是否滿足要求,如果空間不夠會自動擴(kuò)容,所以不會導(dǎo)致緩沖區(qū)溢出的問題。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評論 2 373