本文主要分析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);