redis原始碼分析與思考(八)——物件
阿新 • • 發佈:2018-12-14
談及物件,我們不免會立即聯想到Java、C++等面向物件的語言,而在C中是沒有物件這一說法的,為了方便管理與程式碼整體的優化,redis基於前面幾篇部落格的資料結構自建了一套物件系統。這個系統包含著字串物件、列表物件、雜湊物件、集合物件以及有序集合物件。構建這一物件系統最為直接的好處就是該物件可以根據不同的場景去使用不同的資料結構來實現,提高了效率。 說及物件,當然少不了物件的回收機制,java採用GCC垃圾自動回收機制,而C++使用解構函式來回收物件,redis則實現了基於計數技術的回收機制,當程式中沒有去使用該物件時,便對其進行回收,同樣redis也實現了物件共享機制,當建立一個物件時,倘若這個物件已存在,那麼便共享原來的物件空間。
物件
首先來看下在redis中如何定義的物件:
#define REDIS_LRU_BITS 24
typedef struct redisObject {
// 型別
unsigned type:4;
// 編碼
unsigned encoding:4;
// 物件最後一次被訪問的時間
unsigned lru:REDIS_LRU_BITS;
// 引用計數
int refcount;
// 指向值物件的指標
void *ptr;
} robj;
其中在結構體中refcount表示該物件被引用的次數,為0時,回收該物件。值得一提的是:
unsigned type:4;
這個語法的意思是申請4B的空間給type,型別不確定。而在redis中,我們是通過鍵值對的形式來存貯資料的,而從物件的角度看,每次存貯的時候,都會建立兩個物件,鍵物件與值物件。
編碼型別
下面列出物件編碼與物件型別:
// 物件型別
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
// 物件編碼
#define REDIS_ENCODING_RAW 0 /* Raw representation */
#define REDIS_ENCODING_INT 1 /* Encoded as integer */
#define REDIS_ENCODING_HT 2 /* Encoded as hash table */
#define REDIS_ENCODING_ZIPMAP 3 //已棄用
#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
在前面幾篇部落格中有提到,一個物件的底層實現有多種可能,現在列出它們之間的對應關係:
物件型別 | 物件編碼 | 資料結構 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT、REDIS_ENCODING_EMBSTR、REDIS_ENCODING_RAW | 整數、embstr編碼格式sds、raw編碼格式sds |
REDIS_LIST | REDIS_ENCODING_ZIPMAP、REDIS_ENCODING_LINKEDLIST | 壓縮列表、雙端連結串列 |
REDIS_SET | REDIS_ENCODING_INTSET、REDIS_ENCODING_HT | 整數集合、字典 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST、REDIS_ENCODING_ZIPLIST | 跳躍表、壓縮列表 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST、REDIS_ENCODING_HT | 壓縮列表、字典 |
物件的建立
robj *createObject(int type, void *ptr) {
robj *o = zmalloc(sizeof(*o));
o->type = type;
//因為有鍵物件與值物件,鍵物件預設的是字串物件,raw編碼
o->encoding = REDIS_ENCODING_RAW;
o->ptr = ptr;
o->refcount = 1;
//設定最後一次訪問的時間
o->lru = LRU_CLOCK();
return o;
}
字串物件
字串物件的底層有著三種實現結構:整數、embstr編碼的sds字串、raw編碼的sds字串。