Redis原理:IntSet

(笔记总结自b站黑马程序员课程)

一、结构

IntSet是Redis中set集合的一种实现方式,基于整数数组来实现,并且具备长度可变、有序等特征。 结构如下:

typedef struct intset {uint32_t encoding; //编码方式uint32_t length; //元素个数int8_t contents[]; //整数数组
} intset;

注意整数数组记录的是每一个数的起始地址,决定数字长度是编码方式。

其中的encoding包含三种模式,表示存储的整数大小不同:

#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))

为了方便查找,Redis会将intset中所有的整数按照升序依次保存在contents数组中,结构如图:

现在,数组中每个数字都在int16_t的范围内,因此采用的编码方式是INTSET_ENC_INT16,每部分占用的字节大小为:

①encoding:4字节(固定)

②length:4字节(固定)

③contents:2字节 * 3 = 6字节  

二、扩展 

我们向该其中添加一个数字:50000,这个数字超出了int16_t的范围,intset会自动升级编码方式到合适的大小。 以当前案例来说流程如下:

  • 升级编码为INTSET_ENC_INT32, 每个整数占4字节,并按照新的编码方式及元素个数扩容数组

  • 倒序依次将数组中的元素拷贝到扩容后的正确位置(倒序可以规避数据覆盖问题)

  • 将待添加的元素放入数组末尾

  • 最后,将inset的encoding属性改为INTSET_ENC_INT32,将length属性改为4

三、源码

源码理解就行,注意插入数据底层用到了二分查找的算法。

插入新数据:

/* Insert an integer in the intset */
intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {//获取当前值编码uint8_t valenc = _intsetValueEncoding(value);//要插入的位置uint32_t pos;if (success) *success = 1;/* Upgrade encoding if necessary. If we need to upgrade, we know that* this value should be either appended (if > 0) or prepended (if < 0),* because it lies outside the range of existing values. *///判断编码是否超过当前intset的编码if (valenc > intrev32ifbe(is->encoding)) {//超出编码,需要升级/* This always succeeds, so we don't need to curry *success. */return intsetUpgradeAndAdd(is,value);} else {//在当前intset中查找值与value一样元素的角标pos/* Abort if the value is already present in the set.* This call will populate "pos" with the right position to insert* the value when it cannot be found. */if (intsetSearch(is,value,&pos)) {if (success) *success = 0; //如果找到了,则无需插入,直接结束并返回失败return is;}//数组扩容is = intsetResize(is,intrev32ifbe(is->length)+1);//移动数组中pos之后的元素到pos+1,给新元素腾出空间if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);}//插入新元素_intsetSet(is,pos,value);//重置元素长度is->length = intrev32ifbe(intrev32ifbe(is->length)+1);return is;
}

升级编码方式:

/* Upgrades the intset to a larger encoding and inserts the given integer. */
static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {//获取当前inset编码uint8_t curenc = intrev32ifbe(is->encoding);//获取新编码uint8_t newenc = _intsetValueEncoding(value);int length = intrev32ifbe(is->length); //获取元素个数//判断新元素是大于0还是小于0,小于0插入队首,大于0插入队尾int prepend = value < 0 ? 1 : 0;//重置编码为新编码/* First set new encoding and resize */is->encoding = intrev32ifbe(newenc);//重置数组大小is = intsetResize(is,intrev32ifbe(is->length)+1);/* Upgrade back-to-front so we don't overwrite values.* Note that the "prepend" variable is used to make sure we have an empty* space at either the beginning or the end of the intset. *///倒序遍历,诸葛搬运元素到新的位置while(length--)_intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));/* Set the value at the beginning or the end. *///插入新元素,prepend决定是队首还是队尾if (prepend)_intsetSet(is,0,value);else_intsetSet(is,intrev32ifbe(is->length),value);//修改数组长度is->length = intrev32ifbe(intrev32ifbe(is->length)+1);return is;
}

四、总结

Intset可以看做是特殊的整数数组,具备一些特点:

  • Redis会确保Intset中的元素唯一、有序

  • 具备类型升级机制,可以节省内存空间

  • 底层采用二分查找方式来查询

注意:一般适合在数据量不是很多的情况下使用 

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

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

相关文章

读取XML的几种方式

一、为什么使用XML 1、便于不同应用程序之间通信。 2、便于不同平台之间通信。 3、便于不同平台之间数据共享。 二、Dom读取 xml文件内容 <?xml version"1.0" encoding"UTF-8"?> <bookstore><book id"1"><name>冰…

归并排序-面试例子

小数和问题 描述 在一个数组中&#xff0c;一个数左边比它小的数的总和&#xff0c;叫数的小和&#xff0c;所有数的小和累加起来&#xff0c;叫数组小和。求数组小和。 例子 5 2 6 1 7 小和原始的求法是&#xff1a;任何一个数左边比它小的数累加起来。 5左边比它小数累加…

面试系列 - Redis持久化机制详解

目录 一、Redis 持久化机制 二、混合使用 RDB 和 AOF 三、 RDB(Redis DataBase)详解 四、AOF&#xff08;Append-Only File&#xff09;详解 Redis 是一个内存数据库&#xff0c;为了持久化数据以确保数据不会在服务器重启时丢失&#xff0c;Redis 提供了两种主要的持久化机…

执行 JUnit 单元测试前,修改环境变量

同一份代码&#xff0c;在不改变配置文件的情况下&#xff0c;可以连接不同的数据库&#xff0c;进行JUnit测试。 非开发、测试、生产环境的区别。而是 我就站在这里&#xff0c;指哪打哪&#xff01; 避免重复造轮子&#xff0c;参考博文&#xff1a; 使用junit&spri…

python main 函数-启动-传递参数 python 打包 exe C# 进程传参

Part1:Python main 传递参数 在Python编程中&#xff0c;我们经常需要从命令行或其他外部环境中获取参数。Python提供了一种简单而灵活的方式来处理这些参数&#xff0c;即通过main函数传参 1.python main 函数-启动-传递参数 test.py import sysdef main():# 获取命令行参…

QT 自定义信号

自定义信号&#xff0c;需要 1.在singnals:区域下写信号函数&#xff0c;以及函数对应的参数 2. 需要emit关键字进行发射信号 3. 在需要处理该信号的其他类中&#xff0c;建立信号和其信号槽函数connect() 4. 在其他类中创建信号处理槽函数 #include "mythread.h"my…

Linux 中的 col 命令及示例

Linux 系统中的col命令用于过滤掉反向换行,使输出看起来更加正确,只有正向和半正向换行,并尽可能用制表符替换空白字符。这在处理 nroff 和 tbl 的输出时被证明是有用的。col 实用程序只是从标准输入读取并写入标准输出。 句法: 列 [-bfhpx] [-l num] col [-bfhpx] [-l nu…

C盘清理教程

C盘清理教程 首先使用space Sniffer 扫一下c盘&#xff0c;然后看一下到底是哪个文件这么大 第二步&#xff0c;创建软链接。 首先将我们需要移动的文件的当前路径拷贝下来&#xff1a;C:\Users\Tom\Desktop\test-link\abc\ghi.txt 然后假设剪切到D盘下&#xff1a;D:\ghi.…

Linux 中的 cmp 命令及示例

Linux/UNIX 中的cmp命令用于逐字节比较两个文件,帮助您找出两个文件是否相同。 当 cmp 用于比较两个文件时,如果发现差异,则将第一个不匹配的位置报告到屏幕,如果没有发现差异,即比较的文件相同。cmp 不显示任何消息,如果比较的文件相同,则仅返回提示。语法: cmp [选项…

基于改进人工蜂群算法的 K 均值聚类算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

RBTree模拟实现

一、概念 概念&#xff1a;红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出俩倍&a…

pdf拆分成多个文件的方法以及注意事项

PDF是一种非常流行的文件格式&#xff0c;但有时候我们需要将一个大的PDF文件拆分成多个小的文件&#xff0c;以便于管理和分享。本文将介绍一些拆分PDF文件的方法以及需要注意的事项。 AdobeAcrobat是一款专业的PDF编辑软件&#xff0c;可以轻松地拆分PDF文件。以下是使用Adob…

基于SpringBoot开发的停车位管理系统(调用百度地图api)

文章目录 项目介绍主要功能截图:前台:后台部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot开发的停车位管…

【建站教程】使用阿里云服务器怎么搭建网站?

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网以搭建WordPress网站博客为例&#xff0c;阿小云来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流程&#x…

Fiddler Inspectors AES解密插件开发

Fiddler Inspectors AES解密插件开发 业务数据做了AES加密处理&#xff0c;抓包看不到具体数据&#xff0c;找不到合适的插件 就自己动手写了一个&#xff0c;主要是使用fiddler提供的一个基类和三个接口 Inspector2, IRequestInspector2, IResponseInspector2&#xff0c; IB…

【2023研电赛】兆易创新命题三等奖: 低成本单母线电流永磁同步无感驱动器

本文为2023年第十八届中国研究生电子设计竞赛兆易创新企业命题三等奖以及决赛最佳论文奖分享&#xff0c;参加极术社区的【有奖活动】分享2023研电赛作品扩大影响力&#xff0c;更有丰富电子礼品等你来领&#xff01;&#xff0c;分享2023研电赛作品扩大影响力&#xff0c;更有…

通过阿贝云免费云服务器部署vue3+vite项目

通过阿贝云免费云服务器部署vue3vite项目 阿贝云&#xff1a;https://www.abeiyun.com 首先访问阿贝云登录后申请服务器&#xff0c;需要关注微信公众号绑定 然后我们给服务器安装操作系统&#xff0c;这里我使用了centos7.6 这里我使用finalshell 连接服务器 我们首先配置ng…

EPICS电机支持(asynMotor)

EPICS电机支持 1&#xff09; 顶层对象是EPICS motor记录 已经对这个对象编写了很多代码&#xff1a;spec&#xff0c;IDL和Python类等 2&#xff09;下一层是EPICS设备支持 了解motor记录&#xff0c;与驱动会话 3&#xff09;最底层是EPICS驱动 对motor记录一无所知&am…

如何提取视频中的音频?几个步骤轻松提取

在现今社交媒体的风靡下&#xff0c;许多人都会使用手机录制视频来记录生活中的美好瞬间。有时候&#xff0c;我们也会想要提取视频中的音频&#xff0c;例如将自己的演讲录音分发给听众。本文将会介绍如何在手机上提取视频中的音频以及需要注意的事项。 使用应用程序 首先&am…

Linux命令200例:write用于向特定用户或特定终端发送信息

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0…