整体数据结构:链式hash解决hash冲突、采用渐进式hash来完成扩容过程。
/** 哈希表节点*/
typedef struct dictEntry {// 键void *key;// 值union {void *val;uint64_t u64;int64_t s64;} v;// 指向下个哈希表节点,形成链表struct dictEntry *next;} dictEntry;/** 字典类型特定函数*/
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;/* This is our hash table structure. Every dictionary has two of this as we* implement incremental rehashing, for the old to the new table. */
/** 哈希表** 每个字典都使用两个哈希表,从而实现渐进式 rehash 。*/
typedef struct dictht {// 哈希表数组dictEntry **table;// 哈希表大小unsigned long size;// 哈希表大小掩码,用于计算索引值// 总是等于 size - 1unsigned long sizemask;// 该哈希表已有节点的数量unsigned long used;} dictht;/** 字典*/
typedef struct dict {// 类型特定函数dictType *type;// 私有数据void *privdata;// 哈希表:两个Hash表,里面存储的是键值对,交替使用,用于rehash操作dictht ht[2];// rehash 索引// 当 rehash 不在进行时,值为 -1int rehashidx; /* rehashing not in progress if rehashidx == -1 */// 目前正在运行的安全迭代器的数量int iterators; /* number of iterators currently running */} dict;
2、扩容函数 static int _dictExpandIfNeeded(dict *d)
触发该函数的三个操作:添加修改场景下会触发。
dictAdd:用来往 Hash 表中添加一个键值对。
dictRelace:用来往 Hash 表中添加一个键值对,或者键值对存在时,修改键值对。
dictAddorFind:间接调用 dictAddRaw。_dictExpandIfNeeded->_dictKeyIndex->dictAddRaw
static int _dictExpandIfNeeded(dict *d) 里面的代码片段截取//扩容两个条件// 1)字典已使用节点数趋近用完,并且没有开启aof和rdb两个操作// 2)Hash表承载的元素个数已是当前大小的5倍if (d->ht[0].used >= d->ht[0].size &&(dict_can_resize ||d->ht[0].used/d->ht[0].size > dict_force_resize_ratio)){// 新哈希表的大小至少是目前已使用节点数的两倍// T = O(N)return dictExpand(d, d->ht[0].used*2);}//以下代码可以发现,但凡开启rdb和aof两个操作,必定禁止rehash。
void dictEnableResize(void) {dict_can_resize = 1;
}void dictDisableResize(void) {dict_can_resize = 0;
}void updateDictResizePolicy(void) {if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)dictEnableResize();elsedictDisableResize();
}