Redis inset内部结构

ntset 和 dict 都是 sadd 命令的底层数据结构,当添加的所有数据都是整数时,会使用前者;否则使用后者。特别的,当遇到添加数据为字符串,即不能表示为整数时,redis 会把数据结构转换为 dict,即把 intset 中的数据全部搬迁到 dict。

整数集合的应用

Intset 是set的底层实现之一,如果一个集合:
1. 只保存着整数元素;
2. 元素的数量不多;
那么 Redis 就会使用 intset 来保存集合元素

intset 结构体

intset 底层本质是一个有序的、不重复的、整型的数组,支持不同类型整数

  1: typedef struct intset {
  2:     // 每个整数的类型
  3:     uint32_t encoding;
  4:  
  5:     // intset 长度
  6:     uint32_t length;
  7:  
  8:     // 整数数组
  9:     int8_t contents[];
 10: } intset;

encoding 的值可以是以下三个常量的其中一个 :
# define INTSET_ENC_INT16 (sizeof(int16_t))
# define INTSET_ENC_INT32 (sizeof(int32_t))
# define INTSET_ENC_INT64 (sizeof(int64_t))
contents 数组是实际保存元素的地方,数组中的元素有以下两个特性:
• 没有重复元素;
• 元素在数组中从小到大排列;
contents 数组的 int8_t 类型声明比较容易让人误解,实际上,intset 并不使用 int8_t 类型来保存任何元素,结构中的这个类型声明只是作为一个占位符使用:在对 contents 中的元素进行读取或者写入时,程序并不是直接使用 contents 来对元素进行索引,而是根据 encoding的值,对 contents 进行类型转换和指针运算,计算出元素在内存中的正位置。在添加新元素,进行内存分配时,分配的容量也是由 encoding 的值决定。

inset操作

升级

在添加新元素时,如果 intsetAdd 发现新元素不能用现有的编码方式来保存,它就会将升级集合和添加新元素的任务转交给 intsetUpgradeAndAdd 来完成

intsetUpgradeAndAdd 需要完成以下几个任务:
1. 对新元素进行检测,看保存这个新元素需要什么类型的编码;
2. 将集合 encoding 属性的值设置为新编码类型,并根据新编码类型,对整个 contents 数
组进行内存重分配。
3. 调整 contents 数组内原有元素在内存中的排列方式,让它们从旧编码调整为新编码。
4. 将新元素添加到集合中。
整个过程中,最复杂的就是第三步,让我们用一个例子来理解这个步

 

假设有一个 intset ,里面包含三个用 int16_t 方式保存的数值,分别是 1 、2 和 3 ,它的结
构如下:
intset->encoding = INTSET_ENC_INT16;
intset->length = 3;
intset->contents = [1, 2, 3];
其中,intset->contents 在内存中的排列如下:
image

现在,我们要要将一个长度为 int32_t 的值 65535 加入到集合中,intset 需要执行以下步骤:
1. 将 encoding 属性设置为 INTSET_ENC_INT32 。
2. 根据 encoding 属性的值,对 contents 数组进行内存重分配。
重分配完成之后,contents 在内存中的排列如下:

image

contents 数组现在共有可容纳 4 个 int32_t 值的空间。
3. 因为原来的 3 个 int16_t 值还“挤在”contents 前面的 48 个位里,所以程序需要对它们
进行移动和类型转换,从而让它们适应集合的新编码方式。
首先是移动 3

image

4. 最后,将新值 65535 添加到数组:

intset 搜索

  1: static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
  2:     int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值