1. 介绍
整数集合(intset)是集合键底层实现之一。集合键另一实现是值为空的散列表(hash table),虽然使用散列表对集合的加入删除元素,判断元素是否存在等等操作时间复杂度为O(1),但是当存储的元素是整型且元素数目较少时,如果使用散列表存储,就会比较浪费内存,因此整数集合(intset)类型因为节约内存就存在。
散列表的实现
2. 整数集合结构的实现
|
|
3. 升级
intset整数集合之所以有三种表示编码格式的宏定义,是因为根据存储的元素数值大小,能够选取一个最”合适”的类型存储,”合适”可以理解为:既能够表示元素的大小,又可以节省空间。
因此,当新添加的元素,例如:65535,超过当前集合编码格式所能表示的范围,就要进行升级操作。
我们使用刚才命令中的集合,它在结构如下图:
[url01]
3.1获得新元素的编码格式
当前新元素要插入到集合中时,首先就要判获得新元素的编码格式,所以调用_intsetValueEncoding()来返回一个”适合”该元素的编码格式。65535的最”适合”的编码格式是INTSET_ENC_INT32。
3.2 调整内存空间
当得到新元素的编码格式后,就要将集合中所有元素的编码格式都要变成升级后的编码格式,因此,需要调整集合数组contents的内存空间大小,调用intsetResize()函数。
- intrev32ifbe()是一个宏定义,定义和实现在redis根目录下的endianconv.h和endianconv.c中根据主机字节序用来做整数大小端的转换。
已经获知65535的编码格式,因此调整内存空间的大小等于编码格式的大小乘以集合元素的个数。如果图:
[url02]
注意:encoding成员已经发生变化,但是length并没有更新。
3.3 根据编码格式设置对应的值
调整好内存空间后就根据编码格式来设置集合元素的值和最后将新元素添加到集合中,都调用_intsetSet()函数。
- memrev16ifbe()是一个宏定义,定义和实现在redis根目录下的endianconv.h和endianconv.c中根据主机字节序用来做内存大小端的转换。
将集合中原来的元素和新插入的元素以”合适”的编码格式INTSET_ENC_INT32写到数组中,顺序过程如下图:
[url03]
最后要更新length。
3.4 升级实现源码
|
|
3.5 升级的特点
- 提升灵活性:因为C语言是静态类型的语言,通常在在数组中只是用一种类型保存数据,例如,要么只用int16_t类型,要么只用int32_t类型。通过自动升级底层数组来适应不同类型的新元素,不必担心类型的错误。
- 节约内存:整数集合既可以让集合保存三种不同类型的值,又可以确保升级操作只在有需要的时候进行,这样就节省了内存。
- 不支持降级:一旦对数组进行升级,编码就会一直保存升级后的状态。
4.整数集合的其他操作
源代码注释下载:redis源码注释