您的位置:首页 > 数据库 > Redis

Redis 字典的实现(2)

2015-06-27 15:47 726 查看
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完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: