Redis 字典的实现(2)

1.Redis 字典 Hash算法

根据key计算hash值

hash = dict -> type -> hashFunction(key);

根据sizemask属性和哈希值,计算出索引,ht[x]可以是ht[0]或ht[1]

index = hash & dict -> ht[x].sizemask;

Redis使用MurmurHash2算法计算键的哈希值,优点在于即使输入的键是有规律的,算法仍能给出一个很好的随机分布性。


2.解决Hash冲突

当2个或多个不同对象的Hash值相同时,会被分配到哈希表的同一个索引上,此时就称之为哈希冲突。

Redis采用链地址法解决键冲突,每个哈希节点都有一个next指针,由此指针构成一个单向链表,新添加的元素在链表表头。


3.rehash

负载因子 = 哈希表节点数量/哈希表大小

load_factor = ht[0].used / ht[0].size

当哈希表的操作不断进行,需要把哈希表的负载因子保持在一个合理范围内,需要对哈希表进行扩容或缩容操作,2种操作都通过执行再散列操作来执行(rehash):

a.为字典的ht[1]分配空间,如果是扩容操作,ht[1]的空间为ht[0]的节点数量2倍;如果是缩容,ht[1]的空间为ht[0]节点数量的一半。

b.将ht[0]中的所有键值对rehash到ht[1]上面:rehash需要重新计算键的哈希值和索引值,然后放在ht[1]的指定位置上。

c.当ht[0]所有键值对都迁移到ht[1]上之后,释放ht[0],就是将ht[0]表置为空表,再将ht[1]置为ht[0],并将ht[1]新建一个大小为0的空哈希表。


4.渐进式rehash

上面讲到rehash过程中,需要将ht[0]上的键值对迁移到ht[1]上,但这个过程并不是一次性操作完成的。如果需要一次性完成,就必须对当前哈希表进行锁表操作,锁表期间会导致服务的不可用,所以rehash操作需要分多次、渐进式的完成。

a.为ht[1]分配空间,字典同时持有ht[0]和ht[1]两个哈希表

b.将rehashidx值置为0,表示rehash工作开始。

c.rehash期间,所有对字典执行的读写操作,都会在ht[0]和ht[1]两个表上操作,读操作如果在ht[0]上找到,会把结果rehash到ht[1]上,如果未找到会到ht[1]上去找,保存操作只会存在ht[1]上,当rehash工作完成之后,rehashidx++;

d.随着字典操作的不断执行,最终ht[0]上所有节点会全部rehash到ht[1]上,这时将rehashidx值置为-1,表示rehash完成。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值