一、字典的实现
使用哈希表作为底层实现,一个哈希表里可以用多个哈希表节点,而每个哈希表节点保存字典中的一个键值对。
二、哈希算法
当要将一个新的键值对添加到字典中时,需要先根据键算出它的哈希值和索引值,再根据索引值,将包含新键值对的哈希表节点放到哈希数组指定的索引上。
三、解决哈希冲突
当由两个或者两个以上数量的键被分配到了哈希数组的同一个索引上时,则我们称这些键发生了冲突。
Redis的哈希表采用链地址法来解决键冲突,每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单项链表。被分配到同一个索引上的多个节点可以用这些单向链表连接起来,这就解决了键冲突问题。
四、Rehash(重新散列)
为了让哈希表的浮在因子维持在一个合理的范围内,当哈希表保存的健值对数量太多或者太少时,程序需要对哈希表的大小进行相应的扩展或者收缩。这里可以利用Rehash(重新散列)操作来完成扩展和收缩哈希表的工作。
过程:
1、为字典的ht[1]哈希表分配空间,空间大小分配的规则是:
1)扩展操作:ht[1]的大小是第一个大于等于ht[0].used*2 的 (2的n次方幂)
2)收缩操作: ht[1]的大小为第一个大于等于ht[0].used的(2的n次方幂)
2、将保存在ht[0]中的所有健值对rehash到ht[1]上面:rehash是指重新计算键的哈希值和索引值,然后将健值对防止在ht[1]哈希表的指定位置。
3、当ht[0]包含的所有健值对都迁移到了ht[1]之后,释放ht[0],将ht[1]设置为ht[0],并在ht[1]新创建一个空白哈希表,为下次refresh做准备。
对哈希表进行扩展与收缩的条件:
1、扩展操作的条件:
服务器目前没有执行BGSAVE命令或者BGREWITEAOF命令,并且哈希值的浮在因子大于等于1。
服务器执行BGSAVE命令或者BGREWITEAOF命令,并且哈希表的浮在因子大于等于5。
2、收缩操作:
哈希表的负载因子小于0.1时,收缩操作。
五、渐进式rehash
哈希表里保存的键值对有成千上亿个的话,不是一次性rehash,而是分多次、渐进式完成。
参考文献
1、redis设计与实现 黄建宏