这几天研究go和php中map的实现,捎带着看了看redis中字典的实现
redis 中也是采用拉链发来处理hash冲突,实现和老版本的php hashtable的实现方式差不多,链式分散式存储,但是多了个rehash(渐进式hash),来看下redis中每个结构的定义
dict的定义
typedef struct dict {
dictType *type; // 类型特定函数 type 指向 操作字典增删改查的函数
void *privdata; // 私有数据 保存着不同类型需要传递给type函数的可选参数 说白了不同类型选择不同的操作函数
dictht ht[2]; // 保存两个hash表,ht[1]在扩容的时候会用到,是ht[0]的2倍
int rehashidx; // rehash 索引 当rehash不进行时为-1
} dict;
dictht的定义
typedef struct dictht {
dictEntry **table; // hash数组,元素为指向dicEntry的指针
unsigned long size; // hash表的大小
unsigned long sizemask; // hash 表的掩码 size-1
unsigned long used; // hash表已使用的大小
} dictht;
dictEntry的定义
typedef struct dictEntry {
void *key; //键值
union { // 值
void *val;
uint64_t u64;
int64_t s64;
} v;
struct dictEntry *next; //指向hash冲突的下一个元素
} dictEntry;
hashmap 结构图如下
渐进式hash
redis中字典的扩容不是一次搬迁完成的,是在每次查询和更新的时候完成的,当操作字典的某个key的时候,判断rehash 不为-1,并且存在在ht[0]中,搬迁到ht[1],并减少ht[0].used,知道userd为0,ht[1]变成ht[0]