字典实现
哈希表
/* * 哈希表 * * 每个字典都使用两个哈希表,从而实现渐进式 rehash 。 */typedef struct dictht { // 哈希表数组 dictEntry **table; // 哈希表大小 unsigned long size; // 哈希表大小掩码,用于计算索引值 // 总是等于 size - 1 unsigned long sizemask; // 该哈希表已有节点的数量 unsigned long used; } dictht;
哈希表节点
/* * 哈希表节点 */typedef struct dictEntry { // 键 void *key; // 值 union { void *val; uint64_t u64; int64_t s64; } v; // 指向下个哈希表节点,形成链表 struct dictEntry *next;} dictEntry;
字典
/* * 字典 */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;
字典类型特定函数
redis会为用途不同的字典设置不同的类型特点函数
/* * 字典类型特定函数 */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;
哈希算法
# 使用字典设置的哈希函数,计算key的哈希值hash = dict->type->hashFunction(key);# 使用哈希表的sizemask属性和哈希值,计算出索引值index = hash & dict->ht[x].sizemask;
建冲突
redis采用链地址法解决冲突,新节点添加到链表的表头位置。
rehash
扩展:ht[1]的大小为第一个大于等于ht[0].used*2的2的n次方幂;
收缩:ht[1]的大小为第一个大于等于ht[0].used*2的的2^n;
将ht[0]上的所有键值对rehash到ht[1]上
扩展与收缩的条件:
没有BGSAVE或者BGREWRITEAOF命令,负载因子大于等于1;
有BGSAVE或者BGREWRITEAOF命令时,负载因子大于等于5;
负载因子= ht[0].used / ht[0].size
渐进式rehash
渐进式rehash期间,删除,查找,更新等操作会在两个哈希表执行,但是添加操作在ht[1]执行。
渐进式rehash将对转移操作平均到对字典的每个添加、删除、查找、更新操作上,避免一次集中操作。
作者:峰巢
链接:https://www.jianshu.com/p/ae7bf57d72e7