集合对象的编码可以是intset和hashtable之一,相对于其他类型的结构集合就要简单的多。
intset编码
intset编码的集合对象底层实现是整数集合,所有元素都保存在整数集合中。
typedef struct intset{
//编码方式
uint32_t encoding;
//集合包含的元素数量
uint32_t length;
//保存元素的数组
int8_t contents[];
}intset;
整数集合的每个元素都是 contents 数组的一个数据项,它们按照从小到大的顺序排列,并且不包含任何重复项。
length 属性记录了 contents 数组的大小。
需要注意的是虽然 contents 数组声明为 int8_t 类型,但是实际上contents 数组并不保存任何 int8_t 类型的值,其真正类型有 encoding 来决定。
升级
当我们新增的元素类型比原集合元素类型的长度要大时,需要对整数集合进行升级,才能将新元素放入整数集合中。具体步骤:
- 根据新元素类型,扩展整数集合底层数组的大小,并为新元素分配空间。
- 将底层数组现有的所有元素都转成与新元素相同类型的元素,并将转换后的元素放到正确的位置,放置过程中,维持整个元素顺序都是有序的。
- 将新元素添加到整数集合中(保证有序)。
升级能极大地节省内存。
降级
整数集合不支持降级操作,一旦对数组进行了升级,编码就会一直保持升级后的状态。
hashtable编码
hashtable编码的集合对象底层实现是字典,字典的每个键都是一个字符串对象,保存一个集合元素,不同的是字典的值都是NULL。具体参考哈希类型。
集合对象编码转换:
* 集合对象使用intset编码需要满足两个条件:一是所有元素都是整数值;二是元素个数小于等于512个;不满足任意一条都将使用hashtable编码。
* 以上第二个条件可以在Redis配置文件中修改et-max-intset-entries选项。