1. 程式人生 > 其它 >Redis之簡單動態字串SDS

Redis之簡單動態字串SDS

技術標籤:redisredis

1.用途

Redis並未使用c語言的string,而是自己構建簡單動態字串(SDS,simple dynamic string)抽象型別表示字串.

​ c語言string只是用在不需要修改的地方,例如日誌列印.其他地方基本都是SDS,例如:

redis>RPUSH fruit "apple" "banana" "cherry"

除了儲存字串值外,還用於緩衝區buffer:

​ AOF中AOF緩衝區,客戶端狀態中輸入緩衝區

2.定義

SDS:
struct sdshdr{
	int len;	//記錄buf陣列已使用位元組數=SDS儲存字串長度
	int free;	//buf陣列中未使用位元組數
	char buf[]; //位元組陣列char型別陣列,儲存字串
}

key(就是sdshdr),free,len,buf. 其中buf指向char陣列,其中儲存sds字串內容,以\0結尾,free和len都不計算\0所佔空間

例如free=5,len=5,buf指向的為sds字串佔用5個,\0佔用1個,空佔用5個.有空畫圖

3.SDS與c字串區別

### 3.1 常數複雜度獲取字串長度

​ 由於記錄了len,所有strlen獲取字串長度O(1),c中遍歷O(n)

3.2 杜絕緩衝區溢位

c中字串不記錄長度容易造成緩衝區溢位,sds api修改sds時,api先檢查空間是否足夠,不夠自動空間擴充套件後再修改(全自動避免緩衝區溢位)

3.3減少修改字串時帶來的記憶體重分配次數

SDS通過未使用空間接觸了字串長度和底層陣列長度之間的關聯.有了free屬性在,buf陣列長度不一定是+1,因為其中可以包含未使用位元組.

​ 未使用空間幫助SDS實現了 1.空間預分配 2.惰性空間釋放 兩種優化策略

3.3.1.空間預分配(增)

​ 用於優化SDS字串增長操作.

​ 對SDS進行空間擴充套件時,不僅給SDS分配修改所必需的空間,還會給SDS分配額外未使用空間:

​ 如果修改後SDS長度(len)小於1MB,分配與len同樣的未使用空間(len*2).實際長度變成len(SDS修改後實際長度)+len(未使用空間)+1byte,不計入len長度

​ 如果修改後SDS長度(len)大於等於1MB,分配1MB未使用空間,實際長度變成len(SDS修改後實際長度)+1MB(未使用空間)+1byte,1byte就是\0

多分配的未使用空間使增長n次字串需要的記憶體重分配次數從必定n次變成最多n次

3.3.2.惰性空間釋放(減)

​ 用於優化SDS字串縮短操作

​ 需要縮短SDS儲存的字串時,不立即使用記憶體重分配縮短多餘位元組,而是使用free記錄多餘位元組等以後使用.

sdstrim(s,"xy")==>a,b,c,\0移動到最左,x,y空間清空,保留未使用空間.len=3,free=9,\0

以後擴增SDS時,如果free足夠,不需要執行記憶體重分配,直接使用未使用空間.

3.4 二進位制安全

​ c語言字串不能存圖形等,如果包含空字元,會被認為字串結尾,限制C語言字串不能存圖片等.

​ SDS處理存放在buf陣列中的資料不會做任何改變,所以buf屬性被稱為位元組陣列--->redis不是用buf位元組陣列儲存字元,而是儲存二進位制資料.

​ 1.儲存二進位制資料,存入資料不變化.

​ 2.用len屬性而不是空字串或者判斷字串是否結束

4.SDS API

​ sdsnew:建立包含給定c字串的sds

​ sdsempty:建立空sds

​ sdsfree:釋放sds

​ sdslen:返回len(byte數)

​ sdsavail:返回free(byte)

​ sdsdup:建立給定sds副本(copy)

​ sdsclear:清空sds中字串

​ sdscat:將給定c字串拼接到sds字串末尾

​ sdscatsds:將給定sds字串拼接到sds字串末尾

​ sdscpy:將給定c字串複製到sds,覆蓋sds原有字串

​ sdsgrowzero:用空字串將sds擴充套件到給定長度

​ sdsrange:保留sdsd給定區間內資料,不在區間內資料會被覆蓋或清除

​ sdstrim:從給定sds左右兩端移除所有在給定c字串中出現過的字元

​ sdscmp:對比兩個sds字串是否相同