字典哈希表的实现原理_Redis的Hash底层是如何实现的?

853be0efd8945322270f59f0bee5aea6.png

你好,是我琉忆。

上一篇我们主要介绍了String和List的底层实现原理,今天我们来说说Hash的数据结构。

哈希作为我们常见的一种数据结构,那么在Redis中它是怎么实现的呢?

01

Hash的数据结构

Redis 中的hash,内部是由 HashTable 或者 ziplist实现的。而HashTable 的内部结构是由数组加链表的二维结构实现的。它包含若干个 key-value,key 不重复。

首先我们来看看HashTable内部实现结构:

实现的流程:

78ab1915df601e6c3adbadf0311040b6.png

实现的源码:

/* * 哈希表节点 */typedef struct dictEntry {    // 键    void *key;    // 值    union {        void *val;        uint64_t u64;        int64_t s64;    } v;    // 指向下个哈希表节点,形成链表    struct dictEntry *next;} dictEntry;/* * 哈希表 *  * 每个字典都使用两个哈希表,从而实现渐进式 rehash 。 */typedef struct dictht {    // 哈希表数组    dictEntry **table;    // 哈希表大小    unsigned long size;    // 哈希表大小掩码,用于计算索引值    // 总是等于 size - 1    unsigned long sizemask;    // 该哈希表已有节点的数量    unsigned long used;} dictht;

那么HashTable是如何实现扩容的呢?

02

HashTable的扩容流程

扩容流程如下:

6761dd379e419a3104601229bdabe1b2.png

首先我们要知道,Redis 扩容采用的是渐进式 Hash 的方式进行扩容。原来的 hash 表是 h[0],然后加倍 size 生成一个新的 hash 表 h[1],然后在定时任务中,渐渐地将 h[0] 中的内容迁移到 h[1] 中。

执行下面的操作时,内部的实现步骤: 

  • 读操作:先去 h[0] 中找,找不到再去 h[1] 中去找。

  • 写操作:直接写在 h[1] 中

  • 删除操作和读操作类似

根据上面的流程,我们来按步骤看看它的内部扩容实现:

需要知道的是:哈希表内部是由数组加链表实现的。

步骤一:新建一个 H[1],为字典 h[1] 分配空间,hash 表初始化的状态就有一个 h[0] 和 h[1]。

int _dictInit(dict *d, dictType *type,        void *privDataPtr){    // 初始化两个哈希表的各项属性值    // 但暂时还不分配内存给哈希表数组    _dictReset(&d->ht[0]);    _dictReset(&d->ht[1]);    // 设置类型特定函数    d->type = type;    // 设置私有数据    d->privdata = privDataPtr;    // 设置哈希表 rehash 状态    d->rehashidx = -1;    // 设置字典的安全迭代器数量    d->iterators = 0;    return DICT_OK;}

具体的实现在 dict.c 中的 dictExpand 这个方法。此时 dicth[1] 指向一个数组table[]。

哈希表初始状态:

dae6b76eea4b465282da0fad52431668.png

为 h[1] 分配空间:

3655debd2df6c616bb865da9ab827bae.png

步骤二:将 h[0] 中的所有键值对,rehash 到 h[1] 上,rehash 是指重新计算哈希值和索引值。将键值对放到 h[1] 上面的指定位置。

ab8f66c8d729e9de3aaa4865f1aed51f.png

步骤三:当h[0] 中包含的键值对都迁移到了 h[1] 上面,需要释放 h[1],并将 h[1] 设置为 h[0],并在 h[1] 新创建一个空白哈希表,为下次 rehash 准备。

3989684d2f3766512d0482feae4f8afd.png

自此Hash实现扩容。这就是哈希表完成一个完整的扩容过程。

zplist我们在下一篇和集合一起讲解。

942503e366a5147fad50b5608b158587.png

 后话

    是否觉得小小的哈希不简单。学完这篇文章后是否有耳目一新又重新认识了一次哈希?希望你能够继续跟着我的步伐往后看,下一篇我们讲讲集合的数据结构。

8d41a886d3fb2f8f6a7bf17b28ecd126.gif

如果你觉得好,可以点个赞哦~

aa1a9f696d9e088123766149922739c8.png aa1a9f696d9e088123766149922739c8.png

往期精选

  • PHP面试常考内容之Memcache和Redis(1)

  • PHP面试常考内容之Memcache和Redis(2)

  • PHP面试之面向对象(1)

  • PHP面试常考内容之面向对象(2)

  • PHP面试常考内容之面向对象(3)

83bd9aa65e3c0aa2cb34ee49b24a497b.png

如有疑问或想跟我交流,

可以加我的个人微信:leoyistar

关注琉忆编程库,PHP面试资料都在这

c052bd613117d56a6a857469edeb56b2.png db0513f598a07723eeceb26b2700f253.gif

点击“好看”,让更多人看到~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值