hashtable的结构和扩容机制

结构

最外层封装了dictht,结构如下
在这里插入图片描述
table指向了实际存储的hash结构dictEntry。size是哈希表大小,也就是说dictEntry有多少空间。sizemask是掩码,为固定值size-1,然后元素的index就应该是元素哈希值&sizemask。used代表dictEntry里面多少个坑位已经被用上了。假设index冲突了,用拉链法(头插,避免尾插法遍历到尾巴这一O(n)的时间开销)解决。

扩容机制

触发扩容机制有两种情况,一种是负载因子>=1且没有在执行BGSAVE或BGREWRITEAOF命令,另一种是负载因子>=5。负载因子就是used/size
分别说明如下:

  • 负载因子>=1,说明此时基本dictEntry上每个坑位都有一个链表了,查找时候时间复杂度达不到O(1)了,假设没在执行BGSAVE或者BGREWRITEAOF就进行扩容。因为扩容是主进程推进的,这俩机制会创建子进程,假设此时扩容,相当于主进程在写入,子进程还在复制,内存开销很大
  • 负载因子>=5,那此时哈希表已经不堪重负了,无论如何顶着压力也得扩容。

那么具体扩容机制是啥呢?其实是叫做渐进扩容,就是不是说一口气把旧表迁移过去新表,这样数据多的话会阻塞。实际的思想是一种顺带着做的感觉,就是每次增删改查哈希表时候顺带着迁移一下(注意,这里意思是,步骤3hashtable里有[a, b, c, d]我可能rehashindex是0,那我此时要迁移的是a,时机是我要增删改查一个元素(可能是b或者c都有可能)了)。
以下是哈希表渐进式 rehash 的详细步骤:

  1. 为 ht[1] 分配空间, 让字典同时持有 ht[0] 和 ht[1] 两个哈希表。
  2. 在字典中维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示 rehash 工作正式开始。
  3. 在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值增一。
  4. 随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被 rehash 至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1 , 表示 rehash 操作已完成。

注意

因为在进行渐进式 rehash 的过程中, 字典会同时使用 ht[0] 和 ht[1] 两个哈希表, 所以在渐进式 rehash 进行期间, 字典的删除(delete)、查找(find)、更新(update)等操作会在两个哈希表上进行: 比如说, 要在字典里面查找(删除和修改本质也需要先找到)一个键的话, 程序会先在 ht[0] 里面进行查找(还没被迁移走), 如果没找到的话(已经被迁移走了), 就会继续到 ht[1] 里面进行查找。

另外, 在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 ht[1] 里面, 而 ht[0] 则不再进行任何添加操作: 这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 61
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值