【Redis】基础数据结构-quicklist
Redis List
在Redis3.2版之前,Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis使用压缩列表实现,否则Redis使用双向链表实现。
ziplist存在问题
-
不能保存过多的元素,否则查找复杂度高,性能降低。
-
由于每个节点保存了前一个节点的长度,不同长度使用的字节数不一样,所以在更新节点的时候有可能引起长度的变化导致连锁更新问题。
为了解决上面两个问题,在Redis3.2版之后,引入了quicklist。
quicklist
quicklist可以理解为是ziplist和链表的结合体,一个quicklist是一个双向链表,链表中的每一个节点是一个ziplist。
quicklist结构定义
typedef struct quicklist {// 头指针quicklistNode *head;// 尾指针quicklistNode *tail;unsigned long count; /* 列表中的元素总个数,也就是所有ziplist中包含的元素数量之和 */unsigned long len; /* 链表中节点的个数 */int fill : QL_FILL_BITS; /* 表示ziplist的大小 */unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */unsigned int bookmark_count: QL_BM_BITS;quicklistBookmark bookmarks[];
} quicklist;
-
head:指向头结点的指针
-
tail:指向尾节点的指针
-
count:列表中的元素总个数,等于所有节点的ziplist中包含的元素数量之和
-
len:quicklist中quicklistNode节点的个数
-
fill:用来限制quicklistNode中ziplist的大小,为正数时代表ziplist中最多能包含的元素个数,为负数时有以下几种情况:
数值 含义 -1 表示ziplist的字节数不能超过4KB -2 表示ziplist的字节数不能超过8KB -3 表示ziplist的字节数不能超过16KB -4 表示ziplist的字节数不能超过32KB -5 表示ziplist的字节数不能超过64KB
除此之外,也可以通过list-max-ziplist-size参数配置最大的字节数。
quicklistNode结构定义
typedef struct quicklistNode {// 前一个节点struct quicklistNode *prev;// 下一个节点struct quicklistNode *next;// 指向ziplist压缩列表的指针unsigned char *zl;unsigned int sz; /* ziplist压缩列表的字节数 */unsigned int count : 16; /* ziplist压缩列表的元素个数 */unsigned int encoding : 2; /* 编码格式:RAW==1 or LZF==2 */unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */unsigned int recompress : 1; /* 是否被压缩 */unsigned int attempted_compress : 1; /* 是否可以被压缩 */unsigned int extra : 10; /* 预留bit位*/
} quicklistNode;
quicklist创建
quicklist *quicklistCreate(void) {struct quicklist *quicklist;// 分配空间quicklist = zmalloc(sizeof(*quicklist));// 初始化头尾节点quicklist->head = quicklist->tail = NULL;quicklist->len = 0;quicklist->count = 0;quicklist->compress = 0;// 默认为-2,表示ziplist的字节数最大不能超过8KBquicklist->fill = -2;quicklist->bookmark_count = 0;return quicklist;
}
添加元素
添加元素的时候可以在链表的头部或者尾部进行添加,以头部添加为例:
- 首先调用_quicklistNodeAllowInsert方法判断是否允许添加元素到ziplist,如果允许,调用ziplistPush方法进行添加
- 如果_quicklistNodeAllowInsert不允许添加元素,则需要新创建一个quicklistNode,然后将元素添加到新创建的quicklistNode的压缩列表中
// 从头部添加元素
int quicklistPushHead(quicklist *quicklist, void *value, size_t sz) {quicklistNode *orig_head = quicklist->head;// 判断是否允许添加if (likely(_quicklistNodeAllowInsert(quicklist->head, quicklist->fill, sz))) {// 将元素添加到ziplitquicklist->head->zl =ziplistPush(quicklist->head->zl, value, sz, ZIPLIST_HEAD);quicklistNodeUpdateSz(quicklist->head);} else {// 新创建quicklistNode节点quicklistNode *node = quicklistCreateNode();// 添加元素node->zl = ziplistPush(ziplistNew(), value, sz, ZIPLIST_HEAD);quicklistNodeUpdateSz(node);_quicklistInsertNodeBefore(quicklist, quicklist->head, node);}// 更新数量quicklist->count++;quicklist->head->count++;return (orig_head != quicklist->head);
}
_quicklistNodeAllowInsert
_quicklistNodeAllowInsert方法用于判断是否允许在某个quicklistNode指向的压缩列表中添加元素。
在quicklist的结构体定义中,fill指定了ziplist中能包含的最大元素个数或者ziplist最大的字节数,_quicklistNodeAllowInsert方法就是判断ziplist中的元素个数或者ziplist的字节数是否超过了限制:
// node:当前的quicklistNode节点
// fill:ziplist中能包含的最大元素个数或者ziplist最大的字节数
// sz:要添加元素的大小
REDIS_STATIC int _quicklistNodeAllowInsert(const quicklistNode *node,const int fill, const size_t sz) {if (unlikely(!node))return 0;int ziplist_overhead;/* 判断要添加元素的大小是否小于254 */if (sz < 254)ziplist_overhead = 1;elseziplist_overhead = 5;/* 判断要添加元素的大小是否小于64 */if (sz < 64)ziplist_overhead += 1;else if (likely(sz < 16384))ziplist_overhead += 2;elseziplist_overhead += 5;/* 计算添加元素后的当前的quicklistNode的大小 + 新加入元素的大小 + 插入元素后ziplit的prevlen占用大小 */unsigned int new_sz = node->sz + sz + ziplist_overhead;// 判断添加元素后的ziplist的字节数是否超过了fill中设置的大小if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(new_sz, fill)))return 1;else if (!sizeMeetsSafetyLimit(new_sz))return 0;else if ((int)node->count < fill) // 判断ziplist的元素个数是否超过了fill设置的大小return 1;elsereturn 0;
}
总结
-
在Redis3.2版之前,Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis使用压缩列表实现,否则Redis使用双向链表实现。
-
为了解决压缩列表在节点多的时候查找效率低的问题以及连锁更新问题,在Redis3.2版之后引入了quicklist,quicklist是一个双向链表,链表中的每一个节点是一个ziplist。
-
quicklist中限定了ziplist的大小,如果超过了限制的大小,新加入元素的时候会生成一个新的quicklistNode节点。
-
quicklist通过限定ziplist的大小来保证一个ziplist中的元素个数不会太多,如果需要连锁更新,也只在某个quicklistNode节点指向的ziplist中更新,不会引发整个链表的更新,以此来解决压缩列表存在的问题。
参考
陈雷《Redis5设计与源码分析》
极客时间 - Redis源码剖析与实战(蒋德钧)
Redis版本:redis-6.2.5
相关文章:
【Redis】基础数据结构-quicklist
Redis List 在Redis3.2版之前,Redis使用压缩列表和双向链表作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis使用压缩列表实现,否则Redis使用双向链表实现。 ziplist存在问题 不能保存过多的元素,否则查找复杂度…...
QT 实现服务器客户端搭建
1. 服务器头文件 #ifndef SER_H #define SER_H#include <QWidget> #include<QTcpServer> //服务器头文件 #include<QTcpSocket> //客户端头文件 #include<QMessageBox> //消息对话框 #include<QList> //链表头文件QT_BEGIN_NAM…...
Javascript - 轮播图
轮播图也称banner图、广告图、焦点图、滑片。是指在一个模块或者窗口,通过鼠标点击或手指滑动后,可以看到多张图片。这些图片统称为轮播图,这个模块叫做轮播模块。可以通过运用 javascript去实现定时自动转换图片。以下通过一个小Demo演示如何运用Javascript实现。 <!DOCTYP…...
MATLAB中syms函数使用
目录 语法 说明 示例 创建符号标量变量 创建符号标量变量的向量 创建符号标量变量矩阵 管理符号标量变量的假设 创建和评估符号函数 syms函数的作用是创建符号标量和函数,以及矩阵变量和函数。 语法 syms var1 ... varN syms var1 ... varN [n1 ... nM] …...
竞赛选题 深度学习 opencv python 实现中国交通标志识别_1
文章目录 0 前言1 yolov5实现中国交通标志检测2.算法原理2.1 算法简介2.2网络架构2.3 关键代码 3 数据集处理3.1 VOC格式介绍3.2 将中国交通标志检测数据集CCTSDB数据转换成VOC数据格式3.3 手动标注数据集 4 模型训练5 实现效果5.1 视频效果 6 最后 0 前言 🔥 优质…...
Qt 关于mouseTracking鼠标追踪和tabletTracking平板追踪的几点官方说明
mouseTracking属性用于保存是否启用鼠标跟踪,缺省情况是不启用的。 没启用的情况下,对应部件只接收在鼠标移动同时至少一个鼠标按键按下时的鼠标移动事件。 启用鼠标跟踪的情况下,任何鼠标移动事件部件都会接收。 部件方法hasMouseTrackin…...
基于springboot的论坛网站
目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 普通管理员管理 交流论坛 交流论坛评论 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了…...
分库分表理论总结
一、概述 分库分表是在面对高并发、海量数量时常见的数据库层面的解决方案。通过把数据分散到不同的数据库中,使得单一数据库的数据量变小来缓解单一数据库的性能问题,从而达到提升数据库性能的目的。比如:将电商数据库拆分为若干独立的数据…...
RK3568平台开发系列讲解(外设篇)AP3216C 三合一环境传感器驱动
🚀返回专栏总目录 文章目录 一、AP3216C 简介二、AP3216C驱动程序2.1、设备树修改2.2、驱动程序沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在本篇将介绍AP3216C 三合一环境传感器的驱动。 一、AP3216C 简介 AP3216C 是由敦南科技推出的一款传感器,其支持环境光…...
ES 关于 remote_cluster 的一记小坑
最近有小伙伴找到我们说 Kibana 上添加不了 Remote Cluster,填完信息点 Save 直接跳回原界面了。具体页面,就和没添加前一样。 我们和小伙伴虽然隔着网线但还是进行了深入、详细的交流,梳理出来了如下信息: 两个集群:…...
第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第四节 - Python 中的字符串反转6种不同的方式方法)
Python 字符串库不支持内置的“ reverse() ”,就像其他 python 容器(如 list)所做的那样,因此了解其他反转字符串的方法可能会很有用。本文讨论了在Python中实现它的几种方法。 目录 Python 中使用循环反转字符串 在Python中使用递归反转字符串...
el-date-picker增加默认值 修改样式
预期效果 默认是这样的 但希望是直接有一个默认的当天日期,并且字体颜色啥的样式也要修改(在这里假设今天是2023/10/6 功能实现 踩了坑挺多坑的,特此记录 官方文档 按照官方的说明,给v-model绑定一个字符串就可以了 在j…...
Hive中生成自增序列的常用方法
在日常业务开发过程中,通常遇到需要hive数据表中生成一列唯一ID,当然连续递增的更好。 最近在结算业务中,需要在hive表中生成一列连续且唯一的账单ID,于是就了解生成唯一ID的方法 1. 利用row_number函数 语法:row_n…...
4.MySql安装配置(更新版)
MySql安装配置 无论计算机是否有安装其他mysql,都不要卸载。 只要确定大版本是8即可,8.0.33 8.0.34 差别不大即可。 MySql下载安装适合电脑配置属性有关,一次性安装成功当然是非常好的,因为卸载步骤是非常麻烦的 如果第一次安装…...
使用opencv及FFmpeg编辑视频
使用opencv及FFmpeg编辑视频 1.融合两个视频2.为视频添加声音2.1 安装ffmpy Python包2.2 下载ffmpeg2.3 代码实现 3.效果参考文献 帮朋友做了一个小作业,具体实现分为几个过程: 将两个mp4格式视频融合到一起为新视频添加声音 1.融合两个视频 其中一个…...
Python3 Selenium4 chromedriver Pycharm闪退的问题
Python3版本:3.11.5 Pycharm版本:2023.2.1 Chrome版本:117.0.5938.150(正式版本) 在使用最新版的Selenium4版本时,chromedriver可以驱动Chrome但是闪退,Selenium目前最新版本是4.13.0&#…...
019 基于Spring Boot的教务管理系统、学生管理系统、课表查询系统
基于Spring Boot的教务管理系统、学生管理系统、课表查询系统 一、系统介绍 本作品主要实现了一个课表查询系统,采用了SSM(Spring SpringMVC MyBatis)的基础架构。 二、使用技术 spring-bootspring-MVCthymeleafmybatis-plusdruidLombo…...
包装类?为什么需要包装类?
包装类是一种用于将基本数据类型(如整数、浮点数、字符等)封装成对象的类。在Java和许多其他编程语言中,基本数据类型是不具备面向对象特性的,它们不是对象,不能进行方法调用或参与泛型化。为了弥补这一不足,Java引入了包装类,允许基本数据类型被当作对象来处理。 Java…...
Java中的TCP通信(网络编程 二)
简介 TCP(传输控制协议)是一种在计算机网络中常用的协议,它提供了可靠的、面向连接的通信(协议信息链接:TCP协议)。在Java中,我们可以使用Socket和ServerSocket类来实现TCP通信。 Java TCP通信…...
[架构之路-232]:目标系统 - 纵向分层 - 操作系统 - 数据存储:文件系统存储方法汇总
目录 前言: 一、文件系统存储方法基本原理和常见应用案例: 二、Windows FAT文件系统 2.1 概述 三、Linux EXT文件系统 3.1 基本原理 3.2 索引节点表(Inode Table) 3.2.1 索引节点表层次结构 3.2.2 间接索引表的大小和表项…...
【立体视觉(五)】之立体匹配与SGM算法
【立体视觉(五)】之立体匹配与SGM算法 一、立体匹配一)基本步骤二)局部立体匹配三)全局立体匹配四)评价标准1. 均方误差(RMS)2. 错误匹配率百分比(PBM) 二、半全局(SGM)立体匹配一)代价计算二&a…...
苹果系统_安装matplotlib__pygame,以pycharm导入模块
为了更便捷、连贯的进行python编程学习,尽量在开始安装python软件时,将编辑器、模块一并安装好,这样能避免以后版本冲突的问题。小白在开始安装pycharm、pip、matplotlib往往会遇到一些问题,文中列示其中部分bug,供大家…...
常用颜色的英文和十六进制
以下颜色都是按照下面格式所写 # size:文字大小(1~7);color:文字颜色 <font size5 colorred>红 red #ff0000</font>红 red #ff0000 橙 orange #ffa500 黄 yellow #ffff00 草绿 springgreen #00FF7F 绿…...
计算机网络第二章思考题
1. 调制与编码分别有何作用? 调制(Modulation)和编码(Coding)是通信系统中的两个关键概念,它们分别具有不同的作用和功能: 调制(Modulation): 作用ÿ…...
Xcode、终端、Mason、nvim.debug环境路径
Xcode: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include 终端: /Library/Developer/CommandLineTools/usr/include Mason: /Users/donny/.local/share/nvim/mason/packages/clangd/…...
2023华为OD机试真题-2023(A+B卷)【Java、C++、Go、Python】
【华为OD机试真题-2023(A+B卷)【Java、C++、Go、Python】 该专栏博客已帮助千余名同学通过OD机考 2023年5月,华为OD机考更新为OD统一考试(B卷)。B卷的题目包括两部分: 1.2022年老题库 2.2023新增题目 OD统一考试B卷的题目博主也会及时搜集更新! 以下为OD统一考试(B卷…...
[NISACTF 2022]join-us - 报错注入无列名注入
点击登录,找到注入点 这种框,可以直接爆破关键字,看是否拦截,也可以手动尝试,发现、union、and、or、substr、database等关键字都拦截了 1、学到了:可以用数据库中不存在的表名或者不存在的自定义函数名爆…...
Raid10--Raid01介绍
RAID10 先对磁盘做mirror,然后对整个mirror组做条带化; 比如8块盘 需要分成4个基组,每个基组2块盘; 每个基组先做raid1,再做raid0,4条条带化; 所以: …...
集群服务器
文章目录 项目名:实现集群服务器技术栈通过这项目你学到(或者复习到)实现功能编码环境json环境muduo库boost库MySql数据库登录mysql:查看mysql服务开启了没有?mysql的服务器及开发包库chat,表 allgroup friend groupuser offlinemessage user…...
大数据Doris(五):开始编译 Doris
文章目录 开始编译 Doris 一、下载Doris的安装包 二、解压缩 三、上传配置文件...
汕头哪个公司招聘网页设计/seo综合查询怎么关闭
1.医疗保险产品按照保障责任范畴分为 A.费用补偿型医疗保险和补充型医疗保险 B.费用补偿型医疗保险和定额给付型医疗保险 C.基本型医疗保险和补充型医疗保险 D.费用补偿型医疗保险和基本型医疗保险 E.定额给付型医疗保险和补充型医疗保险 2.()是将医疗服务的提供与偿付结合起…...
天津河西做网站/今日头条权重查询
这题用直接枚举是超时的,必须要用搜索来搜索出所有可能的状态,然后再进行枚举 这是较慢的做法 /* 方格取数,相邻格子的数不可取,问最多取到的和是什么 有点类似炮兵布阵,先打出所有可能的状态,然后dp[i][j…...
西安建设网站公司/百度手机助手免费下载
业务梳理 逻辑回归的数理原理 应用场景 逻辑回归被广泛应用在目标变量是二值变量的场合(0,1) 公式 模型估计 极大似然估计 模型阐释/评估 一个解释变量的阐释图C值/AUC,Lift图得到每个用户的违约概率(信用评分) 目标变…...
商务网站创建/海南百度推广电话
一、设计目的现在的大学占地面积越来越大,建筑物越来越多,功能越来越多样,校内的道路也是纵横交错,校园导航系统可以帮助用户更加快速的了解学校的路线,建筑布局及建筑物的基本信息等(用户主要是新生、家长、教职工、外…...
黑龙江省建设厅网站/线上营销推广方法
一、 构建Https服务器 新建工程 $ cd /home $ express -e ExpressServer $ cd ExpressServer $ sudo npm install 生成证书文件 # 创建一个文件夹存放证书 $ mkdir cert $ cd cert #生成私钥key文件: $ openssl genrsa -out privatekey.pem 1024 #通过私钥…...
什么星网站做调查问卷的/数据分析网站
5G Wifi频段及信道介绍 WiFi 三频AP规划信道时,建议分别采用2.4G、5.2G、5.8G频段可用信道。 2.4G频段; 5.2G频段; 5.8G频段。 中国5G WiFi频段 5.8GHz频段,中国开放只有149、153、157、161、165这5个信道; 其中可支…...