整数集合intset是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合元素数量不多时,redis使用intset作为底层实现
一.整数集合当数据结构
contents数组是整数集合的底层实现,整个集合的每个元素都是contents数组的一个数据项(item),各个项在数组中按从小到大有序的排列,并且数组中元素不重复。
length属性记录了整数集合包含的元素数量,也即是contents数组的长度
虽然intset结构将contents数组声明为int8_t类型的数组,但实际上contents数组并不保存任何int8_t类型的值,contents数组真正的类型取决于enconding属性的值
1.如果encoding属性的值为INTSET_ENC_INT16,那么contents就是一个int16_t类型的数组,数组中的每一项都是int16_t类型的整数值(最小值为-32768,最大值为32767)
2.如果encoding属性的值为INTSET_ENC_INT32,那么contents就是一个int32_t类型的数组,数组中的每一项都是int32_t类型的整数值(最小值为-2147483648,最大值为2147483647)
1.如果encoding属性的值为INTSET_ENC_INT64,那么contents就是一个int64_t类型的数组,数组中的每一项都是int64_t类型的整数值(最小值为-9223372036854775808,最大值为9223372036854775807)
二.升级
当我们要将一个新元素添加的整数集合中时,新元素的类型比现在集合中的现有所有元素的类型都长时,整数集合就先要升级,然后才能将新元素插入到整数集合中
1.升级集合并添加元素共分为三步进行
a.根据新元素类型,扩展整数集合底层数组空间大小,并为新元素分配空间
b.将底层数组现有的所有元素都转换成与新元素相同的类型,并将类型转换后的元素放置到正确的位置上,并且在放置元素的过程中,要维持底层数组的有序性。
c.将新元素添加到底层数组里面
每次向集合中添加元素都可能引起升级,每次升级都需要对底层数组中已有的所有元素进行类型转换,所以添加新元素时的时间复杂度O(N);
2.升级的好处
a.提升灵活性
因为C语言是静态类型语言,为了避免类型错误,我们通常不会将两种不同类型的值放在同一个结构里面,但是因为整数集合通过自动升级底层数组来适应新元素,而不必担心类型错误,所以这种做法很灵活。
b.节约内存
整数集合现在的做法既可以让集合能同时保存三种不同类型的值,又可以确保升级操作只会在需要的时候进行,这可以尽量节约内存;
三.降级
整数集合不支持降级,一旦对数组进行了升级,编码就会一直保持升级后的状态;
本文摘自《redis设计与实现》 黄健宏 著