在 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 ...