Redis设计与实现笔记之字典

news2024/9/21 12:30:17

1.字典的实现

Redis中字典使用的哈希表结构

    typedef struct dictht {
        // 哈希表数组
        dictEntry **table;
        // 哈希表大小
        unsigned long size;
        // 哈希表大小掩码,用于计算索引值
        // 总是等于 size - 1
        unsigned long sizemask;
        // 该哈希表已有节点的数量
        unsigned long used;
    } dictht;

table是一个数组,存放指向entry键值对节点的指针

size则是数组长度。used则是数组中已有entry的数量。

Redis中哈希表节点的结构(dictEntry)

    typedef struct dictEntry {
        // 键
        void *key;
        // 值
        union {
            void *val;
            uint64_t u64;
            int64_t s64;
        } v;
        // 指向下个哈希表节点,形成链表
        struct dictEntry *next;
    } dictEntry;

key键值对中键

v为键值对中的值。v可以为指针也可以为一个整数。

next设计为当出现hash冲突时,冲突的hashentry将放置在当前已存在entry的前面,采用头插法。

这里与HashMap里的hash结构类似,数组+链表的结构,除了hash冲突插入方法有所不同以外,其他很相似。

Redis中字典的结构 (dict)

    typedef struct dict {
        // 类型特定函数
        dictType *type;
        // 私有数据
        void *privdata;
        // 哈希表
        dictht ht[2];
        // rehash 索引
        // 当 rehash 不在进行时,值为 -1
        int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    } dict;

哈希表的dictht的上层结构又封装了一层,这就是字典了。

字典结构的用处就是:

拥有一个*type用来区分不同类型的键值对,为多态字典保留。privdata也是为了多态字典而准备,用于需要传给那些类型特定函数的可选参数。

拥有存放dictht的一个数组,只包含两个哈希表。初始时ht[0]哈希表被具体使用,当rehash时,ht[0]的数据会被rehash到ht[1]。

Redis中dictType结构

    typedef struct dictType {
        // 计算哈希值的函数
        unsigned int (*hashFunction)(const void *key);
        // 复制键的函数
        void *(*keyDup)(void *privdata, const void *key);
        // 复制值的函数
        void *(*valDup)(void *privdata, const void *obj);
        // 对比键的函数
        int (*keyCompare)(void *privdata, const void *key1, const void *key2);
        // 销毁键的函数
        void (*keyDestructor)(void *privdata, void *key);
        // 销毁值的函数
        void (*valDestructor)(void *privdata, void *obj);
    } dictType;

由此结构可见,本结构中具体封装了拥有不同类型的entry的哈希表所对应拥有的不同类型的方法函数。为多态字典准备。

到这里我们知道了从外层到内层的结构为:

dict 字典->dictht 哈希表 -> dictEntry数组table -> dictEntry具体的hash节点(单向链表) ->k,v具体的键值对

2.Redis的rehash操作

很多语言中的hashmap的结构都有rehash操作。redis中操作步骤如下:

1.为hash表重新分配空间

  • 如果执行的是扩展操作, 那么 ht[1] 的大小为第一个大于等于 ht[0].used * 2 的 (2n 次方幂);
  • 如果执行的是收缩操作, 那么 ht[1] 的大小为第一个大于等于 ht[0].used 的 。

如何理解呢,如果是扩容,我们把每个扩容等级想象成上台阶,每一级台阶上可以存放的entry数量为1,2,4,8,16,32...。每次扩容比如entry数量为10时,那么扩容就会扩容到10*2=20,第一个大于等于20的 2的n次方的值就是32,这里大于20的2的n次方的值有32,64,128.....扩容为第一个就行,记得entry的数量要*2

如果是缩容,那么直接缩到当前一个大于等于当前entry数量的一个2的n次方的值就行。比如当前entry为3,那么4就是第一个大于等于3的一个2的n次方的值。

3.Redis的rehash时机

3.1 当以下条件中的任意一个被满足时, 程序会自动开始对哈希表执行扩展操作:

服务器目前没有在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 1

服务器目前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 5

3.2 当哈希表的负载因子小于 0.1 时, 程序自动开始对哈希表执行收缩操作。

3.3 负载因子

    # 负载因子 = 哈希表已保存节点数量 / 哈希表大小
    load_factor = ht[0].used / ht[0].size

4.渐进式rehash

渐进式rehash的意义是为了避免 rehash 对服务器性能造成影响, 服务器不是一次性将 ht[0] 里面的所有键值对全部 rehash 到 ht[1] , 而是分多次、渐进式地将 ht[0] 里面的键值对慢慢地 rehash 到 ht[1]

步骤:

4.1 为 ht[1] 分配空间, 让字典同时持有 ht[0]ht[1] 两个哈希表。

4.2 在字典中维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示 rehash 工作正式开始。

4.3 在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值增一。

4.4 随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被 rehash 至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1 , 表示 rehash 操作已完成。

rehash过程中,增删改查操作有以下特点:

增加只会在ht[1]表中增加,这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。

删除,修改,查找,都会在两张表执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/697990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3D web可视化工具HOOPS Communicator与Autodesk的对比分析

越来越多的开发人员转向基于Web的2D和3D可视化和交互服务。这些使您只需使用网络浏览器即可快速向同事、客户或其他任何人展示设计。该领域的工具提供了大量功能,这些功能可能适合也可能不适合您的特定开发需求。 HOOPS Communicator的原始开发人员之一分享了对该市…

chatgpt赋能python:Python输出NaN的原因及解决方法

Python输出NaN的原因及解决方法 NaN(Not a Number)是一种特殊的数值类型,表示不是一个数字。在Python中,当某种计算结果无法表示为有限数字时,就会输出NaN。本文将介绍Python中输出NaN的原因,并提供一些解…

python: more Layer Architecture and its Implementation in Python

sql server: --学生表 DROP TABLE DuStudentList GO create table DuStudentList (StudentId INT IDENTITY(1,1) PRIMARY KEY,StudentName nvarchar(50),StudentNO varchar(50), --学号StudentBirthday datetime --学生生日 ) go mod…

Qt关闭主窗口后,退出所有异步线程

目录 1.要知道主窗口什么时候关闭2.关闭异步线程 1.要知道主窗口什么时候关闭 在widget.h新增下面的函数 private slots:void closeEvent(QCloseEvent *event);在widget.cpp新增 void Widget::closeEvent(QCloseEvent *event) {qDebug() << "关闭主窗口了&#x…

「网络编程」第三讲:认识协议及简单的协议定制

「前言」文章内容是关于协议的&#xff0c;大致内容是再次认识协议及简单协议的定制&#xff0c;目的是帮助理解协议&#xff0c;下面开始讲解&#xff01; 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」「句子分享」 我与我周…

qt 调节win声音版本大小

QT4 情况下&#xff0c;运行的&#xff0c;会出错&#xff0c;目前暂时没有办法解决在&#xff0c;win下调节音量大小问题在这里插入代码片 参考资料 QT 对window系统下音量的设置和获取 还有个很好贴子&#xff0c;没有找到

LLM 应用参考架构:ArchGuard Co-mate 实践示例

随着&#xff0c;对于 LLM 应用于架构领域探索的进一步深入&#xff0c;以及 ArchGuard Co-mate 开发进入深入区&#xff0c;我们发现越来越多的通用模式。 在先前的文章里&#xff0c;我们总结了一系列的设计原则&#xff0c;在这篇文章里&#xff0c;我们将介绍 ArchGuard Co…

架构重构|性能和扩展性大幅提升的Share Creators智能数字资产管理软件3.0

作为数字资产管理行业的领军者&#xff0c;Share Creators智能数字资产管理软件持续致力于帮助企业和团队智能化管理数字资产&#xff0c;提升工业化管线制作效率。经过本次重构&#xff0c;Share Creators 3.0版本重装上阵&#xff0c;全面更新的服务架构标志着软件整体性能的…

C语言-数字爆炸游戏

问题&#xff1a; 你好&#xff0c;欢迎来到数字爆炸&#xff0c;系统随机生成一个数字&#xff0c;猜大了&#xff0c;提示猜大了&#xff0c;猜小了&#xff0c;提示猜小了。 思路&#xff1a; 先写游戏大概思路首先&#xff0c;会有菜单吧&#xff0c;所以先写一个菜单函数…

服务启动后能ping通但无法访问

近期业务需要&#xff0c;重启了服务器&#xff08;centos 7.4&#xff09;&#xff0c;但是各类服务启动后&#xff0c;仍然无法访问&#xff0c;Nginx的白页面都访问不到&#xff0c;能ping通&#xff0c;nslookup 域名解析也没问题&#xff0c;考虑是防火墙 -- 查看防火墙启…

《2023 信创软件品牌影响力报告》发布!融云入选「信创生态」代表厂商

信创正由试点实践转向全面推广。关注【融云 RongCloud】&#xff0c;了解协同办公平台更多干货。 由于外围环境收紧和国内数字经济高速发展等原因&#xff0c;信创产业在顶层战略的指引推动下蓬勃发展&#xff0c;相关政策有力促进了芯片、操作系统、数据库、办公软件、工业软…

jquery html页面先加载内容过几秒后显示数据

&#x1f607;作者介绍&#xff1a;一个有梦想、有理想、有目标的&#xff0c;且渴望能够学有所成的追梦人。 &#x1f386;学习格言&#xff1a;不读书的人,思想就会停止。——狄德罗 ⛪️个人主页&#xff1a;进入博主主页 &#x1f5fc;推荐专栏&#xff1a;点击进入查看 &a…

文心一言 VS 讯飞星火 VS chatgpt (50)-- 算法导论6.2 2题

二、参考过程 MAX-HEAPIFY&#xff0c;写出能够维护相应最小堆的 MIN-HEAPIFY(A&#xff0c;i)的伪代码&#xff0c;并比较 MIN-HEAPIFY 与 MAX-HEAPIFY 的运行时间。 文心一言&#xff1a; MIN-HEAPIFY(A, i)的伪代码如下&#xff1a; 1.将节点i及其子树中的最小元素交换到…

linux定时清理三个月前的应用日志

目录 思路find 命令需要用到 -mtime n 参数 shell脚本三种方法方法一方法二方法三 配置计划任务 思路 要想删除三个月前的日志&#xff0c;先得找到三个月前的日志才行&#xff0c;可以通过 find命令查找。 find 命令 1.find命令基本介绍     find顾名思义就是查找&…

UMS攸信入选福建省知识产权优势企业名单,为企业自主创新体系建设增添新动能!

近日&#xff0c;根据福建省市场监管局办公室《关于组织开展2023年度省知识产权优势企业申报及复核工作的通知》&#xff08;闽市监办〔2023〕11号&#xff09;要求&#xff0c;将拟确认的2023年福建省知识产权优势企业名单予以公示。 攸信技术成功入选该名单&#xff0c;荣获2…

chatgpt赋能python:Python退出主程序:如何正确结束你的Python代码

Python退出主程序&#xff1a;如何正确结束你的Python代码 对于Python编程的初学者来说&#xff0c;经常会遇到一个问题&#xff1a;如何正确退出Python程序&#xff1f;在Python中&#xff0c;有许多种方式可以停止运行Python程序&#xff0c;但不是所有的方法都是相同的。如…

vue 访问本地json数据

如果你的项目中需要模拟下json数据&#xff0c;来看下访问速度&#xff0c;那就参照这个试试吧&#xff0c;首先创建test.josn&#xff0c;放在pulic目录下&#xff0c;见下图 定义js // 文件 prodOrder.jsexport function test(data) {return request({url: http://localhost…

无缝数据转换!使用C++ 实现 Excel文件与CSV之间的相互转换

CSV格式是一种通用的文本文件格式&#xff0c;可在多个应用程序之间共享和使用。相比之下&#xff0c;Excel文件是一种电子表格格式&#xff0c;通常只能在Microsoft Excel中编辑和查看。因此&#xff0c;将Excel文件转换为CSV格式可使数据更方便地在其他应用程序中使用&#x…

Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论

Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论 我们使用Linux作为服务器操作系统时&#xff0c;为了达到高并发处理能力&#xff0c;充分利用机器性能&#xff0c;经常会进行一些内核参数的调整优化&#xff0c;但不合理的调整常常也会引起意想不到的其他问题&#x…

Android 冷启动优化的3个小案例

背景 为了提高App的冷启动耗时&#xff0c;除了在常规的业务侧进行耗时代码优化之外&#xff0c;为了进一步缩短启动耗时&#xff0c;需要在纯技术测做一些优化探索&#xff0c;本期我们从类预加载、Retrofit 、ARouter方面进行了进一步的优化。从测试数据上来看&#xff0c;这…