Redis 中 IntSet 底层数据结构

IntSet 底层数据结构

序言:

像字符串 SDS 只是保存了一个变量的值,但是像 Redis 中也是需要保存一些集合元素的,这里就介绍一下其中一种集合 IntSet,由于是 Set 所以也有 Set 的一些特性,不过也多加了一些特性:

● 唯一

● 长度可变

● 有序

● 可自动升级

数据结构

这里先来看一下 InSet 的底层结构:

contents数组 :用来保存元素的,用的就是 C 语言里面的数组,不过可以观察到这个数组的类型是 int8_t 就说明这个数组能够存的数字很小(-128~127)。难道这个 IntSet 的数据结构就只能存这些数字吗,其实并不是的,它到底存哪些数字主要由 InSet 的 encoding 字段来控制的,它本身算是充当一个数组的起始地址。
length :表示元素的个数。
encoding :编码方式,支持三种编码方式,这三种方式用来表示存储在数组中的数据能够表示多大,且每一个数字读取的方式和占用数组的大小也不一样。

这里以 16 位来举例:

比如存放一个 16 位能够表示的数字,那么单独放在 8 位的数组中是放不下的,所以在 contents 数组中会以两位来表示一个数字,那么读取的时候也是两位一起读然后转换成一个数字,所以说其实 contents 这个字段充当的是一个数组的起始地址,但是往里面存怎么样的数字和怎么读取都是由 IntSet 来控制的,可以利用多位来表示一个数组。

所以在 IntSet 中读取元素的方式也是有一个计算公式的。

bash 复制代码
startPtr + (sizeof(encoding) * index)

这个公式的具体含义就是,从数组起始地址开始 加上 读取元素索引 * 编码大小,就表示要读到的元素的位置。

由于每种编码的方式不同导致在一个数组中可能一个数占用的大小也不相同,所以需要索引 * 编码的大小。

并且如果读到元素之后也需要同样读取编码大小相同个数的位数才能组成想要的值。

由于要确保这个计算公式的准确性,所以 Inset 中要求存在数组中的编码要统一。

接下来举个例子:

存放5、10、20三个元素。

这里这三个数都在 16 位编码内能够存储,所以采用 16 编码,由于是16位编码,所以这三个元素每个元素都占用数组中的两位,也就是两个字节。

计算一下当前 IntSet 的大小。

● encoding:4 字节

● length:4 字节

● contents:2*3=6 字节

总共是 14 字节。

保存在 IntSet 中的数据也会保持一个有序的状态,为了就是能够使用二分查找法更快的找到元素。

IntSet 自动升级

不过之前说过要求存在 contents 中的数据要求编码必须统一为了方便计算要查找的数据的位置。但是如果有一个数要存到当前数组中,但是它的数对应的编码大于当前编码会怎么办。

这里就涉及到了 IntSet 的升级,会自动把数组中的所有数对应的编码升级。

举例:

例如现在还是存 5,10,20这三个数,对应的编码也是 16 位的。

此时如果向数组中添加一个 50000 超过 16 编码,需要使用 32 位编码,这时候 IntSet 会自动升级,会按照新的编码和元素个数进行数组的扩容。

这时每个元素都需要占用 4 个字节,确保编码的一致性,所以数组需要占用的内存就是(3+1) * 4 == 16 字节

计算完数组的大小之后,就需要将原先的数组中的数据扩大到相对应的编码大小之后,倒序的拷贝到扩容后的数组中。

这里为什么需要倒叙呢?

因为如果正序的话,假设这里是5先转移,那么 5 原先占用 2 个字节,然后扩容到四个字节然后在进行拷贝,在扩容到 4 个字节的时候就会把后面 10 这个数字给覆盖掉了,就导致数据的丢失,但是如果是倒叙,从 20 开始的话,20后面没有数字可以放行的扩容然后转移。所以需要倒倒序。

当转移完成之后:

这时候就可以把新要插入的数据放入到数组的尾部。

最后要修改头信息中的 encoding 和 length。

相关推荐
沐伊~18 分钟前
mysql 安装
数据库·mysql
TimberWill20 分钟前
CONCAT函数使用中出现空指针异常问题分析
数据库
TitosZhang22 分钟前
排序算法稳定性判断
数据结构·算法·排序算法
TDengine (老段)43 分钟前
TDengine 字符串函数 CHAR_LENGTH 用户手册
大数据·数据库·时序数据库·tdengine·涛思数据
wind_one11 小时前
5.基础--SQL--DDL数据库操作
数据库·sql
TDengine (老段)1 小时前
TDengine 数学函数 CRC32 用户手册
java·大数据·数据库·sql·时序数据库·tdengine·1024程序员节
llxxyy卢1 小时前
SQL注入之二次、加解密、DNS等注入
数据库·sql
数据库学啊1 小时前
供暖季技术实战:益和热力用 TDengine 时序数据库破解热力数据处理难题
数据库·时序数据库·tdengine
SEO_juper1 小时前
搜索引擎索引权威指南:抓取、收录与排名的基础
数据库·搜索引擎·seo·数字营销
不剪发的Tony老师1 小时前
SQLite 3.51.0发布,新功能解读
数据库·sqlite