Redis源码学习:quicklist的设计与实现

为什么需要quicklist

假设你已经知道了ziplist的缺陷:

  • 虽然节省空间,但是申请内存必须是连续的,如果内存占用比较多,申请效率低
  • 要存储大量数据,超过了ziplist的最佳上限后,性能有影响

借鉴分片思想,可以把大量的数据分片存储到多个ziplist中,每个ziplist的长度和大小都在最佳上限之下,这样虽然解决了单个ziplist空间申请和数据存储的问题,但是又有了新的挑战:数据拆分后比较分散,不方便查找和管理,多个ziplist如何建立连接呢?这就是下面要说的quicklist。

什么是quicklist

quicklist是一个双端链表结构,链表的每一个节点都是ziplist。

quicklist的结构

// quicklistNode 节点
typedef struct quicklistNode {
    struct quicklistNode *prev;     //前一个quicklistNode
    struct quicklistNode *next;     //后一个quicklistNode
    unsigned char *zl;              //quicklistNode指向的ziplist
    unsigned int sz;                //ziplist的字节大小
    unsigned int count : 16;        //ziplist中的元素个数 
    unsigned int encoding : 2;   //编码格式,原生字节数组或压缩存储
    unsigned int container : 2;  //存储方式
    unsigned int recompress : 1; //数据是否被压缩
    unsigned int attempted_compress : 1; //数据能否被压缩
    unsigned int extra : 10; //预留的bit位
} quicklistNode;

typedef struct quicklist {
    quicklistNode *head;      //quicklist的链表头
    quicklistNode *tail;      //quicklist的链表尾
    unsigned long count;     //所有ziplist中的总元素个数
    unsigned long len;       //quicklistNodes的个数
    ...
} quicklist;

quicklist作为链表结构,它定义了整个链表的头、尾指针,这样一来,就可以O(1)的时间复杂度快速定位链表头和尾了。从quicklist的定义,可以画出quicklist的结构如下:

image.png

为了避免quicklist每个节点下的ziplist的entry过多,在Redis.conf中提供了一个配置项list-max-ziplist-size用来限制数量。如果为正数,则表示ziplist允许的entry的个数的最大值;如果为负数,则表示ziplist的最大内存大小,分下面5种情况:

每个ziplist的内存占用限制(不超过)
-14kb
-28kb,默认值
-316kb
-432kb
-564kb

除了控制ziplist的大小,quicklist还可以对节点的ziplist进行压缩,在Redis.conf种提供了配置项list-compress-depth进行控制。因为quicklist是双端链表,首尾一般访问较多,所以首尾不压缩。这个参数用来控制首尾不压缩的个数。

  • 0:特殊值,代表不压缩。默认值
  • 1:表示首尾各有一个节点不压缩,中间节点压缩
  • 2:表示首尾各有两个节点不压缩,中间节点压缩

插入操作

_quicklistNodeAllowInsert函数用来完成新节点的插入,源码如下:

REDIS_STATIC int _quicklistNodeAllowInsert(const quicklistNode *node,
                                           const int fill, const size_t sz) {
    // new_sz 是新插入元素后 quicklistNode 的总大小,加上 ziplist 的额外开销
    unsigned int new_sz = node->sz + sz + ziplist_overhead;

    // 如果新大小符合优化要求,则允许插入
    if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(new_sz, fill)))
        return 1;

    // 如果不符合优化要求,进一步检查大小是否安全
    // 如果不安全,则不允许插入
    else if (!sizeMeetsSafetyLimit(new_sz))
        return 0;

    // 如果节点中的元素个数少于填充因子,允许插入
    else if ((int)node->count < fill)
        return 1;

    // 否则不允许插入
    else
        return 0;
}

_quicklistNodeAllowInsert函数会计算新插入元素后的大小(new_sz),等于 quicklistNode 的当前大小(node->sz)、插入元素的大小(sz),以及插入元素后 ziplist 的 prevlen 占用大小。然后依次判断新插入的数据大小是否满足要求,即单个 ziplist 是否不超过 8KB,或是单个 ziplist 里的元素个数是否满足要求。只要这里面的一个条件能满足,quicklist 就可以在当前的 quicklistNode 中插入新元素,否则 quicklist 就会新建一个 quicklistNode,以此来保存新插入的元素。

这样一来,quicklist通过控制每个节点种ziplist 的大小或是元素个数,可以有效减少在 ziplist 中新增或修改元素后,发生连锁更新的情况。

总结

本文主要讲解了为了解决ziplist的缺陷,quicklist通过对ziplist进行“分片”存储,限制每个节点的大小或数量来提供性能的方法,希望对你有帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

说说 SSL 的错误认识和不足之处

最近明月在学习折腾 LNMP 期间无意中建了一个 Typecho 的博客小站&#xff0c;近一周的折腾下来&#xff0c;收获真的不少&#xff0c;致使兴趣也越来越浓了&#xff0c;在升级 LNMP 的时候捎带手的给这个 Typecho 博客也启用了 SSL。并且开启了 memcached 和 OPcache 优化加速…

Spring Cache常见问题解决

目录 一 报错:Null key returned for cache operation 二 报错&#xff1a;类型转换异常 三 取出的数据为null 一 报错:Null key returned for cache operation 这里报错有两种情况&#xff1a; 第一&#xff0c;如果你在新增的方法上使用Cacheable注解&#xff0c;那么肯定是…

终极解决方案,传统极速方案,下载软件的双雄对决!

在数字资源日益丰富的今天&#xff0c;下载管理器成为了我们日常生活中不可或缺的工具。市场上两款备受欢迎的下载管理软件——Internet Download Manager&#xff08;IDM&#xff09;和迅雷11&#xff0c;它们以各自的特色和优势&#xff0c;满足了不同用户群体的需求。 软件…

5.3 Python len()函数:获取字符串长度或字节数

Python len()函数详解&#xff1a;获取字符串长度或字节数 Python 中&#xff0c;要想知道一个字符串有多少个字符&#xff08;获得字符串长度&#xff09;&#xff0c;或者一个字符串占用多少个字节&#xff0c;可以使用 len 函数。 len 函数的基本语法格式为&#xff1a; …

python-今年第几天

[题目描述] 定义一个结构体变量&#xff08;包括年、月、日&#xff09;。 计算该日在本年中是第几天&#xff0c;注意闰年问题。输入格式&#xff1a; 年 月 日。输出格式&#xff1a; 当年第几天。样例输入 2000 12 31样例输出 366 数据范围 对于100%的数据&#xff0c;保…

解决MNIST数据集下载慢,或者Http连接失败问题

下载MNIST数据集时遇到速度慢的问题 解决&#xff1a;手动从MNIST数据集的官方网站直接使用下载好的数据文件&#xff0c;放到指定目录下&#xff0c;再进行调取即可。 手动下载地址&#xff1a;MNIST官网 http://yann.lecun.com/exdb/mnist/ 【仍需要连接外网】 这里我提供…

ATA-4052C高压功率放大器在新能源汽车安全测试中的应用

新能源汽车的崛起已经改变了汽车行业的格局&#xff0c;为环境友好型交通方式提供了更多的选择。为了确保这些新型汽车的安全性和可靠性&#xff0c;进行全面的安全测试是至关重要的。高压功率放大器在新能源汽车的安全测试中发挥着重要的作用&#xff0c;本文将介绍其应用以及…

已解决:Vector析构异常Opencv Assert _CrtIsValidHeapPointer

已解决&#xff1a;Vector析构异常Opencv Assert _CrtIsValidHeapPointer 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉…

PathDecider 详细解读

目录 PathDecider的主要功能 PathDecider代码分析 Process() MakeObjectDecision() MakeStaticObstacleDecision() MakeStaticObstacleDecision()的流程图​编辑 MakeStaticObstacleDecision()的代码解析 GenerateObjectStopDecision() PathDecider里用到的其他函数 …

C语言入门4-函数和程序结构

函数举例 读取字符串&#xff0c;如果字符串中含有ould则输出该字符串&#xff0c;否则不输出。 #include <stdio.h>// 函数声明 int getLine(char s[], int lim); int strindex(char s[], char t[]);int main() {char t[] "ould"; // 要查找的目标子字符串…

自然语言处理学习路线(1)——NLP的基本流程

NLP基本流程 【NLP基本流程】 0. 获取语料 ——> 1. 语料预处理 ——> 2. 特征工程&选择 ——> 3. 模型训练 ——> 4. 模型输出&上线 【NLP基本流程图】 Reference 1. 自然语言处理(NLP)的一般处理流程&#xff01;-腾讯云开发者社区-腾讯云 2. …

Vatee万腾平台:智能科技的领航者

随着科技的飞速发展&#xff0c;数字化转型已成为企业、行业乃至整个社会不可逆转的趋势。在这个变革的浪潮中&#xff0c;Vatee万腾平台凭借其卓越的技术实力、前瞻的战略眼光和卓越的服务品质&#xff0c;成为了智能科技的领航者。 Vatee万腾平台致力于为企业提供全方位的数字…

【Python机器学习】利用t-SNE进行流形学习

虽然PCA通常是用于变换数据的首选方法&#xff0c;使你能够用散点图将其可视化&#xff0c;但这一方法的性质限制了其有效性。 有一类用于可视化的算法叫做流形学习算法&#xff0c;它允许进行更复杂的映射&#xff0c;通常也可以给出更好的可视化。其中特别有用的一个就是t-S…

google gemini1.5 flash视频图文理解能力初探(一)

市面能够对视频直接进行分析的大模型着实不多&#xff0c;而且很多支持多模态的大模型那效果着实也不好。 从这篇公众号不只是100万上下文&#xff0c;谷歌Gemini 1.5超强功能展示得知&#xff0c;Gemini 1.5可以一次性处理1小时的视频、11小时的音频或100,000行代码&#xff0…

c++设计模式之一创建型模式

1、创建型模式&#xff08;常见的设计模式&#xff09; Factory 模式&#xff08;工厂模式&#xff0c;被实例化的子类&#xff09; 在面向对象系统设计中经常可以遇到以下的两类问题&#xff1a; 下面是第一类问题和代码示例&#xff1a;我们经常会抽象出一些类的公共接口以…

stm32学习笔记---新建工程步骤和点灯演示

目录 STM32的三种开发方式 基于寄存器的方式 基于库函数的方式 基于Hal库的方式 固件库介绍 新建基于标准库的工程步骤 配置寄存器来完成点灯操作 添加库函数来完成点灯操作 添加库函数 开始点灯操作 第一步&#xff1a;使能时钟 第二步&#xff1a;配置端口模式 …

ic基础|功耗篇03:ic设计人员如何在代码中降低功耗?一文带你了解行为级以及RTL级低功耗技术

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

鞠婧祎多个商标被丝芭传媒申请注册!

近日鞠婧祎与丝芭传媒合约引发网络关注&#xff0c;普推商标老杨经检索发现&#xff0c;丝芭传媒早在2016起就申请注册了“鞠婧祎”24个商标&#xff0c;涉及多个商标分类&#xff0c;这些基本都下商标注册证。 不管对经纪公司还是网红公司&#xff0c;有实力的基本都会对旗下的…

# Kafka_深入探秘者(2):kafka 生产者

Kafka_深入探秘者&#xff08;2&#xff09;&#xff1a;kafka 生产者 一、kafka 消息发送流程解析 1、kafka &#xff1a;java 客户端 数据生产流程解析 二、kafka 发送类型 1、kafka 发送类型–发送即忘记&#xff1a;producer.send(record) 同步发送 //通过 send() 发送完…

【Vue3组件】分享一下自己写的简约风格评论区组件

代码比较简单&#xff0c;方便大家二次开发&#xff0c;旨在快速提供基础的样式模板&#xff0c;自行迭代定制 预览 简介 通用评论组件 组件功能 此组件旨在创建一个具备嵌套回复能力的通用评论区域&#xff0c;适用于构建动态、互动性强的用户讨论场景。 接收数据结构 组件通…