每天读一点redis之字典哈希表
字典结构
typedef struct dict{
dictType *type;
void *privdata;
dictht ht[2]; //哈希表 使用ht[0],ht[1]用于rehash
int rehashidx; //当rehash不在进行时,值为-1;记录rehash进度
}dict;
hash值计算公式: hash = dict->type->hashFunction(key);
哈希表结构
typedef struct dictht{
dictEntry **table;
unsigned long size;
unsigned long sizemask; //哈希表大小掩码,用于计算索引值,总是size-1
unsigned long used;
}dictht;
sizemask和哈希值一起决定索引值
index = hash & dict->ht[x].sizemask;
哈希表节点---即是 上述table属性
typedef struct dictEntry{
void *key;
union{
void *val;
unit64_t u64;
int64_t s64;
}v;
struct dictEntry *next; //类似链表,解决bucket中 key 相同时,节点顺序索引
}dictEntry;
解决键冲突: 没有表尾指针,新节点添加到表头位置;
Rehash:
ht[1]分配空间
扩展 size>= ht[0].used *2 的2的n次方
收缩 size>= ht[0].used 的2的n次方
比如 used= 9; 扩展为 2的4次方 = 16;
执行扩展操作
1)没有执行bgsave 或 bgrewriteaof且负载因子>=1
2)正在执行bgsave 或 bgrewriteaof且负载因子>=5 (执行命令执行copy-on-write)提高扩展操作所需的负载因子,避免子进程存在期间进行哈希表扩展操作,节约内存
负载因子 = 哈希表已保存节点数量/哈希表大小
load_factor = ht[0].used/ht[0].size
负载因子小于0.1时,程序自动执行收缩操作
渐进式rehash
靠rehashinx来控制执行进程
字典操作在rehash过程中同时在两个哈希表进行.(delete,find,update)
add操作只保存到ht[1]里,保证ht[0]包含键值对数量只增不减,随着rehash操作执行成为空表
redis使用murmurhash2 计算键的哈希值
No Comments filed.