Redis原码阅读--intset(100)

整数(intset) 【Redis原码阅读--intset(100)】整数集合是集合键的底层实现之一,当一个集合只包含整数元素,并且元素数量不多时,就会用它
整数集合时Redis用于保存数值的,它可以保存int16_t、int32_t、nt64_t
分别对应short int long
insert.h

typedef struct intset {// 编码方式 uint32_t encoding; // 集合包含的元素数量 uint32_t length; // 保存元素的数组 int8_t contents[]; } intset; /* * intset 的编码方式 */ #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也就是char、但是实际上contents不保存任何的char、contents数组真正类型却决与encoding属性的值。
  1. 如果encoding 为INTSET_ENC_INT16、那么contents就是一个int16_t类型的数组,short(最小值-32768、最大值32767)
  2. 如果encoding 为INTSET_ENC_INT32、那么contents就是一个int32_t类型的数组,int(最小值-2147483648、最大值2147483647)
  3. 如果encoding 为INTSET_ENC_INT64、那么contents就是一个int64_t类型的数组,long(太多了)
升级 如果你向一个int类型的数组中,插入了一个long怎么处理? 升级!!!
1、更具新类型的元素,扩展底层数组空间
2、将底层数组现有所有元素都转换为与新元素相同的类型,然后进行一个排序,因为contents是有序不重复的
3、最后才是将新元素添加进去
原数组【1】,【2】,【3】int16_t16*3=48 插入 65535 int32_t 1、重新分配空间大小32*4=128但此时之前的数据位置不变,而是在后面添加空间

Redis原码阅读--intset(100)
文章图片

2、下面就是将转换后元素放到正确的位置,并且要保持有序性不变 先移动3到32*2 ~~~ 32*3-164 ~~ 95

Redis原码阅读--intset(100)
文章图片

因为3的位置换了,所有会有一定的空间空出来 48-63 之后同样的道理移动1和2 最后剩下的位置就是留给新元素的 将encoding从int16_t变为int32_t

每次向整数集合添加元素都可能引起升级,所有添加时O(N)
元素如果很小比如-12145641会出现在头部,元素很大1231564会出现在尾部。
这样的作法就时节约内存,有需要才会升级
整数的集合是不支持降级操作的,一旦升级,encoding就不可能变小了 所有这里就出现一个问题,如果一个数组100个元素,有99个int16,一个int32,那么数组类型就会升级为int32这也时一种浪费,这能不能想办法解决呢?

    推荐阅读