redis源碼淺見之sds

sds是redis項目封裝一個基於字符串操作的庫,其官方解釋爲:"SDSLib 2.0 -- A C dynamic strings library"。

官方下載源碼後上傳至碼雲Redis,頭文件和源文件連接如下:

sds.h

sds.c 

其想法是在保留C語言對字符串操作對同時,還實現了內存管理,節省了使用成本。

實現原理:變長struct。

typedef char *sds;
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

總共五個結構,其他四個大同小異,sdshdr5沒有len和alloc兩個成員,僅做訪問flag獲取類型用。

其他三個的區別在於len和alloc兩個成員的類型不一樣,對應的buf成員的存儲數據量也不一樣,在某些機型下sdshdr32和sdshdr64可能是相同的。

爲了操作的統一性,每個struct對應一個唯一的flag存儲在flags成員的低三位中。

成員解析:

- len:字符串的長度,不包含'\0','\0'由自己維護,用戶不需要關心;

- alloc:申請的內存空間大小;

- flags:類型,當前僅使用低三位,後續可能會有擴展,用於判斷當前sds對應的header的類型;

- buf:變長部分,存儲數據;

 

巧妙之處:

1. 爲了保證C語言原生對字符串對操作,buf定義爲'char *',創建函數返回的是buf成員對應的內存地址,可直接訪問操控,只不過使用typedef重命名爲sds。

2. buf和flags類型相同,根據地址排列關係,buf[-1]正好是flags對應的內存空間,通過flags得到struct類型,進而推算出buf對應的header。當header獲取到時,所有成員可任意訪問。

3. sds定義了一系列的操作函數,考慮到print族函數比較重,結合stdarg.h實現了建議版本的print系列。

 

sds代碼的閱讀難處有三點:變長strcut、地址轉換、define

變長結構:C語言特點,使用方法網上可搜到一大堆;

地址轉換:struct的內存佈局;

define:sdshdr爲數字系列,結合‘##’可拼接出對應的結構名

#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))

 

PS:閱讀redis源碼,特此記憶,望堅持。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章