redis的字典(Hash)
字典(Hash)
Redis的字典是使用HashTable作为底层实现,一个哈希表存储多个键值对节点。
字典结构
typedef struct dict {//类型特定函数dictType *type;//私有数据void *private;//哈希表dictht ht[2];//rehash索引in trehashidx;//当没有进行rehash时,为-1
} dict;
- type是一个在指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定键值对的函数,该字段是为多态字典做准备。
- private属性保存了需要传给dictType中函数的可选参数。
- ht是一个包含两个项的哈希表的数组,当rehash时需要用到第二个作临时存储
Hash表结构
typedef struct dictht {//哈希表数组dictEntry **table;//哈希表大小unsigned long size;//哈希表大小掩码, 用于计算索引值//总是等于size - 1unsigned long sizemask;//该哈希表已有节点的数量unsigned long used;
} dictht;
table 是一个数组,数组中每个元素都是一个指向哈希表节点(dictEntry)结构的指针。
Hash表节点结构
typedef struct dictEntry {//键void *key;//值union{void *val;//可以是指针uint64_tu64;//无符号整数int64_ts64;//带符号整数} v;//指向下个哈希表节点,形成链表(解决哈希冲突)struct dicEntry *next;
} dictEntry;
三者关系
字典------>哈希表------>哈希表节点
哈希算法
下面的代码解释了字典如何根据key计算索引值index
//1、使用字典设置的哈希函数,计算键key的哈希值
hash = dict->type->hashFunction(key)
//2、根据hash值与哈希表掩码相与得到索引值
index = hash & dict->ht[x].sizemask;
解决哈希冲突
当不同的键被分配到同一个哈希表数组索引上(哈希冲突),redis采用链地址法来解决,每一个哈希节点都有一个*next指针,用了指向下一个哈希节点。
- 因为没有一个指向链表尾结点的指针,所以哈希表采用头插入的方式(时间复杂度为O(1)),将新插入的节点插在其他链表节点的首部(如下两图)。
rehash
负载因子==ht[0].used/ht[0].size
什么时候会执行哈希表的扩展与收缩?
当以下条件之一满足时,会对哈希表进行扩展操作
- 服务器没有在执行bgsave(用于在后台异步保存当前数据库的数据到磁盘)与bgrewriteaof(用于异步执行一个 AOF(AppendOnly File) 文件重写操作)命令时,并且哈希表的负载因子大于等于1
- 服务器正在执行bgsave与bgrewriteaof命令,并且哈希表的负载因子大于5(因为每一个哈希表数组节点可能存在大于一个节点,所以会大于1)
当哈希表的负载因子小于0.1时,程序自动开始对哈希表执行收缩
如何执行哈希表的扩展与收缩?
为字典的ht[1]分配内存空间,大小取决于ht[0]的大小,计算如下
如果执行的是扩展操作,ht[1]的大小为第一个大于等于ht[0].used*2的2^n(2的n次方幂)
如果执行的是收缩操作,ht[1]的大小为第一个大于等于ht[0].used的2^n(2的n次方幂)
将保存在ht[0]上的所有键值对重新计算哈希值(rehash)放到ht[1]上
迁移完成后,释放ht[0]并将ht[1]设置为ht[0],并新建一个ht[1]空白哈希表为下一次rehash做准备
rehash并不是一次完成的,而是渐进式完成,步骤如下
为ht[1]分配空间,字典同时持有ht[0]和ht[1]两个哈希表
在字典中位置索引计数器变量rehashix,将他的值设置为0
在rehash期间,每次对字典执行添加、删除、查找或者更新操作时,程序出了执行指定的操作之外,还会将ht[0]在rehashidx索引上的所有键值对rehash到ht[1],完成后将rehashidx自增1
当某个时间点上ht[0]的所有键值对都被rehash成功,程序将rehashidx设为-1
rehash过程中,字典会同时使用两个哈希表,删除,查找,更新操作会在两个表中查找,新增则会直接更新到ht[1]
该文章是学习《redis设计与实现》的读书笔记,如有错误或模糊点请在评论区指针,共同进步共同学习!
redis的字典(Hash)相关推荐
- Redis数据结构为字典Hash 实践 之 系统数据字典实时触发缓存存储
一.项目用redis-learn,文章参考 Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] ...
- Redis数据结构为字典Hash 的 存储、获取、删除等的操作
一.项目用redis-learn,文章参考 Hash底层存储数据的方式确实跟其他数据结构有点不同,其他数据结构几乎都是:Key-Value的存储,而Hash则是:Key – [Field-Value] ...
- Redis 数据结构-字典源码分析
2019独角兽企业重金招聘Python工程师标准>>> 相关文章 Redis 初探-安装与使用 Redis 数据结构-字符串源码分析 本文将从以下几个方面介绍 前言 字典结构图 字典 ...
- 深入redis内部--字典实现
redis的字典定义和实现在dict.h和dict.c文件中. 1.字典结构 typedef struct dict { dictType *type; //定义了字典需要的函数 void *priv ...
- Redis之字典(hashtable)
Redis之字典 字典是什么(hashtable) 总体结构 dict dictht(散列表) dictEntry 如何解决哈希冲突 1. 链表法 2.rehash法 字典是什么(hashtable) ...
- Python操作Redis中的hash
Redis 数据库hash数据类型是一个string类型的key和value的映射表,适用于存储对象.Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿). Python的re ...
- redis中的hash扩容渐进式rehash过程
背景: redis字典(hash表)当数据越来越多的时候,就会发生扩容,也就是rehash 对比:java中的hashmap,当数据数量达到阈值的时候(0.75),就会发生rehash,hash表长度 ...
- Redis的字典扩容与ConcurrentHashMap的扩容策略比较
本文介绍Redis的字典(是种Map)扩容与ConcurrentHashMap的扩容策略,并比较它们的优缺点. (不讨论它们的实现细节) 首先Redis的字典采用的是一种''单线程渐进式rehash' ...
- Redis 哈希(Hash)
为什么80%的码农都做不了架构师?>>> Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 ha ...
最新文章
- Python之collections容器数据类型
- [BUUCTF-pwn]——wdb_2018_2nd_easyfmt
- 百度富文本编辑器的应用技巧---在一个页面中使用多个样式不同功能不同的编辑器...
- django 1.8 官方文档翻译: 2-4-3 模式编辑器
- 008 查看套接字选项是否受支持(获取当前环境下套接字选项默认值)
- 设置HttpClient的授权标头
- 2017 ACM-ICPC北京网络赛: C. Matrix(DP)
- 相机模型与标定(十二)--opencv圆形标志点检测算法
- iOS测试和Android测试的区别
- 成本更低、更优观看体验——自研S265编解码器解析
- jpg转word免费的软件
- 中级计算机软件师考试试题,计算机水平考试-(a)中级软件设计师下午试题模拟64.doc...
- 热门好用的二维码生成器API
- 审计一波appcms-持续更新。
- DBeaver 驱动安装
- 笔记 C++11 std::minmax_element() 的使用(寻找最小值和最大值)
- 高效的APP在线制作平台,让梦想轻松孵化器
- 模拟豆机、高尔顿瓶【java】
- 学渣的刷题之旅 leetcode刷题 27.移除元素
- S40手机上的来电防火墙