Redis 設計與實現 3 字串 SDS

2021-10-13 07:29:21 字數 2767 閱讀 1466

在 redis 中,字串都用自定義的結構簡單動態字串(****** dynamic strings,sds)。

redis 中使用到的字串都是用 sds,例如 key、string 型別的值、sorted set 的 member、hash 的 field 等等等等。。。

資料結構

舊版本的結構

在 3.2 版本之前,sds 的定義是這樣的:

struct sdshdr ;

舊版本 sds 結構示例

這樣的結構有幾個好處:

單獨記錄長度len,獲取字串長度的時間複雜度是 o(1) 。傳統的 c 字串獲取長度需要遍歷字串,直到遇到\0,時間複雜度是 o(n)。

buf 陣列末尾遵循 c 字串以 \0 結尾的慣例,可以相容 c 處理字串的函式。

減少修改字串帶來的記憶體重分配次數,redis 使用了 空間預分配(預先申請大一點點的空間) 和 空間惰性釋放(字串變短修改len欄位即可)來減少字串修改引起的記憶體重新分配。

不以\0為結尾的判斷,二進位制安全。因為等二進位制資料中,可能包含\0,傳統 c 字串一遇到 \0 就認為字串結束了,會導致不能完整儲存。

缺點:len 和 free 的定義用了 4 個位元組,可以表示 2^32 的長度。但是我們實際使用的字串,往往沒有那麼長。4 個位元組造成了浪費。

新版本的結構

舊版本中我們說到,len 和 free 的缺點是用了太長的變數,新版本解決了這個問題。

我們來看一下新版本的 sds 結構。

在 redis 3.2 版本之後,redis 將 sds 劃分為 5 種型別:

型別 位元組 位

sdshdr5 < 1 <8

sdshdr8 1 8

sdshdr16 2 16

sdshdr32 4 32

sdshdr64 8 64

新版本新增加了乙個 flags 欄位來標識型別,長度 1 位元組(8 位)。

型別只占用了前 3 位。在 sdshdr5 中,後 5 位用來儲存字串的長度。其他型別後 5 位沒有用。

structattribute((packed)) sdshdr5 ;

structattribute((packed)) sdshdr8 ;

structattribute((packed)) sdshdr16 ;

structattribute((packed)) sdshdr32 ;

structattribute((packed)) sdshdr64 ;

舊版本 sds 結構示例

優點:舊版本相對於傳統 c 字串的優點,新版本都有

相對於舊版本,新版本可以通過字串的長度,選擇不同的結構,可以節約記憶體

使用attribute((packed)) ,讓編譯器取消結構在編譯過程中的優化對齊,按照實際占用位元組數進行對齊,可以節約記憶體

sds 的初始化

sds 的定義,跟傳統的c語言字串保持型別相容 char *。但是 sds 是二進位制安全的,中間可能包含\0。

sds.h

typedef char *sds;

sds.c

// 初始化 sds

sds sdsnewlen(const void *init, size_t initlen)

case sds_type_8:

// 下面是對 sds_type_16、sds_type_32、sds_type_64 的初始化,跟 sds_type_8 的類似,篇幅有限,省略…

}// 如果 init 非空,則把 init 字串賦值給 s,實際上也是 buf 的初始化

if (initlen && init)

memcpy(s, init, initlen);

// 最後加乙個結束標誌 \0

s[initlen] = 『\0』;

return s;

}sds 的擴/縮容

擴容擴容就不跟初始化一樣寫注釋寫得那麼詳細了,直接拉最重要的幾句**就行。

sds sdsmakeroomfor(sds s, size_t addlen)

縮容sds 縮短不會真正縮小 buf,而是只改長度而已,型別也不變。

sds.c

// 刪掉字串的左右字元中指定的字元

sds sdstrim(sds s, const char *cset)

sds.h

static inline void sdssetlen(sds s, size_t newlen)

break;

case sds_type_8:

sds_hdr(8,s)->len = (uint8_t)newlen;

break;

case sds_type_16:

sds_hdr(16,s)->len = (uint16_t)newlen;

break;

case sds_type_32:

sds_hdr(32,s)->len = (uint32_t)newlen;

break;

case sds_type_64:

sds_hdr(64,s)->len = (uint64_t)newlen;

break;}}

字串 3 字串與函式

字串處理函式,及如何正確返回處理結果?char fun char str str abcde return str void main char str1 10 char str2 fun str1 cout 知識點 1 abcde 儲存在常量區 並非簡單區域性變數,區別於區域性變數陣列 所以可以返...

lua設計與實現(三)字串

lua字串內化的優點 傳統字串的比較與查詢是根據字串長度逐位比較,時間複雜度與字串長度線性相關。而lua的,在已知字串雜湊值的情況下,只需要一次整數比較。多份相同的字串在整個系統中只存在乙份副本。缺點 以前面描述的建立字串的過程來說,在建立乙個新的字串時,首先會檢查系統中是否有相同的資料,只有不存在...

字串python3 python3字串常用方法

整型和布林值的轉換 bin 十進位制轉二進位制 int 1101 2 二進位制轉十進位制 十進位制轉二進位制的演算法 除2 取餘,獲取的所有餘數從下往上進行計算 二進位制轉十進位制的演算法 從右向左,依次乘以2的次方 1101 1 20 0 21 12 2 1 2 3 python2 中有long ...