Redis設計與實現讀書筆記之第一部分: 資料結構與物件
阿新 • • 發佈:2018-12-21
(一) 簡單動態字串SDS
Redis沒有直接使用C語言傳統的字串表示(以空字串結尾的字串),而是構建了簡單動態字串SDS,其定義
struct sdshdr{
int len; //記錄buf陣列中已使用位元組的數量
int free; //記錄buf陣列中未用位元組的數量
char buf[]; //位元組陣列,用於儲存字串
};
SDS相對於C字串的優點
1. O(1)時間內,獲得字串長度
STRLEN命令,直接檢視SDS中的len成員
2. 杜絕緩衝區溢位
因為C字串不記錄自身的長度,所以strcat假定使用者在執行這個函式時,已經為dst分配了足夠多的記憶體,可以容納src字串中的所有內容,而一旦這個假定不成立,就會產生緩衝區溢位。
而在對SDS進行修改之前,API會先檢查SDS空間是否滿足修改所需的要求,如果不滿足的化,API會自動將SDS空間擴充套件到修改所需的大小,然後才執行實際的修改
3.free
(1)空間預留分配
分配空間時,SDS額外分配free空間—>減少連續執行字串增長操作的記憶體重新分配次數
(2)惰性空間釋放
需要縮短SDS儲存的字串時,程式並不立即將多餘的空間釋放,而是使用free成員將位元組的數量記錄起來,等待將來使用。
4.二進位制安全
C字串除了末尾字元外,中間不能包含空字元,是二進位制不安全的,使得C字串只能儲存文字資料,不能儲存影象、音訊、視訊、壓縮檔案等二進位制資料。
而SDS使用len成員標誌資料是否結束。
(二) 連結串列
使用雙向連結串列
typedef struct listNode{
struct listNode* pre;
struct listNode* next;
void* val;
}listNode;
typedef struct list{
listNode* head;
listNode* tail
long len;
void *(*dup)(void *ptr);
void *(*free)(void *ptr);
void *(*match)(void *ptr);
}list;
(三) 字典
字典使用的底層資料結構:雜湊表
1. 雜湊表dictht、雜湊表節點dictEntry
鏈式定址法:總是將產生衝突的新節點插入到連結串列頭部位置。
2. 字典
typedef struct dict{
dtctType* type;
void* privatedata;
dictht ht[2]; //一般只使用ht[0],ht[1]在rehash(重新雜湊)時才使用
int trehashidx; //記錄了rehash的進度,每rehash一次,值+1,(當目前沒進行rehash時,值為-1)
}dict;
3.rehash 重新雜湊
隨著操作的不斷進行,雜湊表儲存的鍵值對會逐漸的增多或減少,為了讓雜湊表的負載銀子維持在一個合理的範圍之內,需要對雜湊表的大小進行相應的擴充套件或收縮
rehash的步驟: 當ht[0]包含的所有鍵值對都遷移到ht[1]之後,ht[0]變為空表,釋放ht[0],將ht[1]設定為ht[0],並在ht[1]新建立一個空白雜湊表,為下一次rehash做準備
4.漸進式rehash
rehash動作不是一次性完成的,而是分多次、漸進式完成的。使用rehashidx來控制,rehashidx=0表示開始rehash,每次rehash操作rehashidx都+1,當rehash執行完畢後rehashidx變為-1.