本文主要分析redis中的dict結構(對應文件dict.h/dict.c)。
一般的dict結構可以利用紅黑數實現,STL中的map便是。redis中的dict結構是用哈希表來實現的,鍵的衝突通過鏈表來解決。
首先看一些基本結構。
hash表節點結構體,除了kv,還有一個next指針,指向下一個節點(衝突的鍵是通過鏈表來解決的)
/*
* 哈希表節點
*/
typedef struct dictEntry {
// 鍵
void *key;
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
// 指向下個哈希表節點,形成鏈表
struct dictEntry *next;
} dictEntry;
字典特定類型函數結構體。每個特定的字典都需要包含一個這個結構體,可以看到該結構體中的成員都是一些函數指針,例如計算key hash值,key複製函數,value複製函數等。這樣做的好處是,抽象。
/*
* 字典類型特定函數
*/
typedef struct dictType {
// 計算哈希值的函數
unsigned int (*hashFunction)(const void *key);
// 複製鍵的函數
void *(*keyDup)(void *privdata, const void *key);
// 複製值的函數
void *(*valDup)(void *privdata, const void *obj);
// 對比鍵的函數
int (*keyCompare)(void *privdata, const void *key1, const void * key2);
// 銷燬鍵的函數
void (*keyDestructor)(void *privdata, void *key);
// 銷燬值的函數
void (*valDestructor)(void *privdata, void *obj);
} dictType;
redis中定義的dict都包含兩個這樣的hash表,用以實現漸進式rehash。
/*
* 哈希表
*
* 每個字典都使用兩個哈希表,從而實現漸進式 rehash 。
*/
typedef struct dictht {
// 哈希表數組
dictEntry **table;
// 哈希表大小
unsigned long size;
// 哈希表大小掩碼,用於計算索引值
// 總是等於 size - 1
unsigned long sizemask;
// 該哈希表已有節點的數量
unsigned long used;
} dictht;
最後來看看dict結構
type是類型的特定函數集合;ht[2]表示兩個hash表;privdata是私有數據;rehashidx是rehash索引;privdata;iterators;
/*
* 字典
*/
typedef struct dict {
// 類型特定函數
dictType *type;
// 私有數據
void *privdata;
// 哈希表
dictht ht[2];
// rehash 索引
// 當 rehash 不在進行時,值爲 -1
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
// 目前正在運行的安全迭代器的數量
int iterators; /* number of iterators currently running */
} dict;
接着看看dict提供的API,主要包括dict的創建、釋放,以及插入、刪除、查找、替換等操作。
dict創建釋放:
dict *dictCreate(dictType *type, void *privDataPtr);
void dictRelease(dict *d);
int dictAdd(dict *d, void *key, void *val);
dictEntry *dictAddRaw(dict *d, void *key);
int dictReplace(dict *d, void *key, void *val);
dictEntry *dictReplaceRaw(dict *d, void *key);
int dictDelete(dict *d, const void *key);
int dictDeleteNoFree(dict *d, const void *key);
dictEntry * dictFind(dict *d, const void *key);
void *dictFetchValue(dict *d, const void *key);
dictEntry *dictGetRandomKey(dict *d);
int dictExpand(dict *d, unsigned long size);
int dictRehash(dict *d, int n);
int dictRehashMilliseconds(dict *d, int ms);
dict迭代器相關
dictIterator *dictGetIterator(dict *d);
dictIterator *dictGetSafeIterator(dict *d);
dictEntry *dictNext(dictIterator *iter);
void dictReleaseIterator(dictIterator *iter);