1. 程式人生 > >Redis設計與實現讀書筆記之第一部分: 資料結構與物件

Redis設計與實現讀書筆記之第一部分: 資料結構與物件

(一) 簡單動態字串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.