1,前言
整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现
Redis的其他数据结构相关如下:
简单动态字符串
链表
字典
2,整数集合
如果一个集合键中,其存储的元素都是整数值时,那么这个整数键的底层实现就会是整数集合
SADD numbers 1 3 5 7 9
# 查看这个集合键底层使用的是什么数据结构
OBJECT ENCODING numbers
2.1,结构
这个整数集合的相关结构如下:
typedef struct intset{
//编码方式
uint32_t encoding;
//集合包含的元素数量
uint32_t length;
//保存元素的数组
int8_t contents[];
} intset;
2.1.1,contents
contents
数组是整数集合的底层实现:整数集合的每个元素都是contents
数组的每一个元素项,每个元素项在数组中按值的的大小从小到大有序地排列,并且数组中不存在重复项
2.1.2,length
该属性记录了contents
数组中元素个数
2.1.3,encoding
虽然在上面提及到contents
是一个int8_t
的数组,但实际上contents
保存什么类型的值取决于encoding
的值
encoding
有如下几种选项:
int8_t
:用8位数字表示一个整数值(最小值是-32768,最大值是32767)int32_t
:用32位数字表示一个整数值(最小值是-2 147 483 648,最大值是2 147 483 647)int64_t
:用64位数字表示一个整数值(最小值是-9 223 372 036 854 775 808,最大值是9 223 372 036 854 775 807)
2.1.4,示例
encoding
的值位INSET_ENC_INT16
表示整数集合的底层实现为int16_t类型的数组,保存的是int16_t
类型的整数值length
属性是5,表示该整数集合存储了五个元素contents
数组按从小到大的顺序存储元素- 因为每个集合元素都是
int16_t
类型的整数值,所以contents
数组的大小等于80位
2.2,升级
假如有一个整数集合A,其内的contents
是int16_t
类型的数组,那么当我们往集合A中存储一个超过int16_t
值范围的整数(假设该整数能用int32_t
存储)时,就会触发升级,将整数集合进行升级
而这个升级步骤是这样的:
- 根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间
- 将底层数组的所有元素都转换为与新元素同类型,并将其放置到正确的位置,并且该过程中需要保证按从小到大的顺序进行存储
- 将新元素添加到底层数组中
- 然后将
encoding
的值改为INSET_ENC_INT32
,并将length
的值从3改为4
升级的好处
整数集合的升级策略有两个好处:
- 提高整数集合的灵活性
- 整数集合可以通过升级底层数组来适应新的元素,让使用者不必担心出现类型错误
- 节约内存
- 升级能让集合同时保存三种不同类型的值(这时的数组类型会为
INSET_ENC_INT64
),又可以确保升级只会在有需要的时候进行
- 升级能让集合同时保存三种不同类型的值(这时的数组类型会为
降级
整数集合不支持降级操作,一旦对数组进行了升级,编码就会一直保持升级的状态