Redis字典结构的理解以及与java hashmap的区别

1.字典的实现

Redis的字典使用哈希表作为底层实现。

1.1 哈希表

Redis字典所使用的哈希表结构定义如下:

typedef struct dictht {

    // 哈希表数组
    dictEntry **table;

    // 哈希表大小
    unsigned long size;

    // 哈希表大小掩码,用于计算索引值
    // 总是等于 size - 1
    unsigned long sizemask;

    // 该哈希表已有节点的数量
    unsigned long used;

} dictht;

table属性是一个数组,数组中的每个元素都指向一个dictEntry结构的指针,每个dictEntry结构保存着一个键值对。

如下图所示为一个空的哈希表

在这里插入图片描述

1.2 哈希表节点

哈希表节点使用dictEntry结构表示,每个dictEntry结构都保存一个键值对:

typedef struct dictEntry {

    // 键
    void *key;

    // 值
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;

    // 指向下个哈希表节点,形成链表
    struct dictEntry *next;

} dictEntry;

1.3 字典

Redis中的字典结果如下:

typedef struct dict {

    // 类型特定函数
    dictType *type;

    // 私有数据
    void *privdata;

    // 哈希表
    dictht ht[2];

    // rehash 索引
    // 当 rehash 不在进行时,值为 -1
    int rehashidx; /* rehashing not in progress if rehashidx == -1 */

} dict;

type属性和privdata属性是针对不同类型的键值对,而创建多态字典而设置的:
type属性是一个指向dictType结构的指针,每个dictType结构保存了一组用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同类型的特定函数。
而privadata属性则保存了需要传给那些类型特定函数的可选参数。

ht属性是一个包含了两个项的数组,数组中每个项都是一个dictht哈希表,一般情况下,字典只使用ht[0]哈希表,而ht[1]哈希表只对ht[0]哈希表进行rehash时使用。

1.4哈希算法和存储了键值对的字典

将一个新的键值对添加到字典里面的时候,程序需要先根据键值对上面的键来计算出哈希值和索引值,然后再根据索引值,将包含新键值对的哈希表节点放到哈希数组的指定索引上面。

Redis计算哈希值和索引值的方法如下:

# 使用字典设置的哈希函数,计算键 key 的哈希值
hash = dict->type->hashFunction(key);

# 使用哈希表的 sizemask 属性和哈希值,计算出索引值
# 根据情况不同, ht[x] 可以是 ht[0] 或者 ht[1]
index = hash & dict->ht[x].sizemask;

下图为添加了键值对后的字典

在这里插入图片描述

2.总结:

redis字典类似于java中的hashmap,可以理解为redis字典封装了哈希表。

Redis字典结构和java中hashmap的区别(抛开语言的角度):

  1. hashmap没有容量缩小的操作,而字典中如果当负载因子小于0.1的时候,程序开始自动对哈希表执行收缩操作

  2. 字典中哈希冲突后采用的链地址法解决冲突,当链表过长的时候没有转化为红黑树,而java中hashmap(jdk1.8)当链表长度超过8,而且数组长度超过64的时候会转为红黑树。(原因:我认为是redis还是更看重内存空间的宝贵性,实现红黑树更耗费内存)

  3. redis 的字典实现rehash的时候采用的是渐进式rehash,也就是rehash这个动作不是一次性集中性完成的。而是分多次渐进式的完成,就是为了避免rehash时间过长导致服务暂停。而java中hashmap是一次完成的

    1. 新创建一个哈希表ht[1],为新表分配空间,此时字典同时持有ht[0],ht[1]两个哈希表
    2. 在字典中维持一个计数器变量rehashidx,初始值为0,表示开始rehash工作
    3. 在rehash期间,对字典的所有增删改查操作都会同时操作两个哈希表,目的是将ht[0]中的健值对重新hash到ht[1]对应位置上,操作完成后rehashidx加1
    4. 随着操作的进行,当ht[0]所有健值对迁移完毕后,rehashidx设置成-1,表示rehash完成。释放ht[0],将ht[1]设置成ht[0],并创建一个空哈希表,为下次rehash做准备。

    在rehash期间增加、删除、查找都会在两个哈希表当中完成,也就是说如果要查找一个key会先去ht[0]当中查找,没找到的话,就去ht[1]当中查找。

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值