redis中字典结构的源码
哈希节点
typedef struct dictEntry {
void *key;
union {//v可以是不同类型的,
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next; //解决哈希冲突使用链地址法
} dictEntry;
//实现多态,对应不同类型的函数实现
typedef struct dictType {
uint64_t (*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;
//哈希表
typedef struct dictht {
dictEntry **table; //哈希表节点数组,存放节点指针
unsigned long size;//表大小
//用来跟计算出的哈希值与求出存放索引,大小为size-1,因为size是2的倍数,所以&计算相当于对size求模
unsigned long sizemask;
unsigned long used;//节点个数
} dictht;
//字典,map
typedef struct dict {
dictType *type; //对应类型,使用他来调用对应的函数
void *privdata; //私有数据????
dictht ht[2];//两个哈希表,使用两个表来实现重新散列
//当rehashidx不为-1时,表示整在重新散列
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
哈希算法使用MurmurHash2
解决哈希冲突,使用链式地址法,每个节点都有个next指针,相同哈希值的节点依次链接起来; 负载因子=已有节点数量/表大小
渐进式rehash
- 为ht[1]分配空间
- 持有rehashidx,当开始rehash时,该值不为-1,然后每次对字典执行一次操作时,会将rehashidx索引上的所有节点rehash到ht[1]上,当全部完成后,rehashidx=0;
- 释放ht[0],将ht[1]设置为ht[0],并为ht[1]新创建一个空白的哈希表;
执行的条件
- 在没有执行
BGSAVE
和BGREWRITEAOF
时,如果负载因子大于等于1,执行rehash - 在执行BDGSAVE和BGREWRITEAOF时,如果负载因子大于等于5,执行rehash
另外:在执行rehash操作时,查找是先在ht[0]中查找,没有再去ht[1]中找;新添加的节点直接存在ht[1]中;