Redis 作为内存存储系统,在内存节约方面肯定会有所特点,而且 Redis 在这方面要求极其苛刻,比较明显的就是 整数集合intset 和 压缩列表ziplist 两个结构
这次我们就以 整数集合 intset 作为主题 ~~~
整数集合intset 是 集合键的底层实现之一
,当一个集合只包含整数元素,而且集合的元素数量不多时(限制值默认 server.set_max_intset_entries = OBJ_SET_MAX_INTSET_ENTRIES = 512),Redis 就会使用整数集合作为集合键的底层实现
整数集合结构
整数集合在 Redis 中用于保存整数值的集合抽象数据结构,它可以保存 int16_t
/ int32_t
/ int64_t
三种类型的整数值,并且保证没有重复;整数集合的结构体如下:
|
|
- 整数集合的每个元素都是 contents[] 数组里面一个 元素,并且按照 大小 升序排列,而且要求数组数字的唯一性,不允许重复
- length 记录了整数集合的 元素个数,也就是 contents[] 数组的长度,所以长度获取复杂度为 O(1)
- 数据类型方面,虽然结构体数组声明的类型为 int8_t,但是存储的时候并不是 int8_t 类型,而是取决于 encoding 属性值,以下为各种属性值对应数字大小范围
INTSET_ENC_INT16
,那么 contents[] 数组的类型就是 int16_t,那么 数组的内存长度就是sizeof(int16_t) * length
,数组内数字大小范围为-32 768 ~ 32 767
INTSET_ENC_INT32
,那么 contents[] 数组的类型就是 int32_t,那么 数组的内存长度就是sizeof(int32_t) * length
,数组内数字大小范围为-2 147 483 648 ~ 2 147 483 647
INTSET_ENC_INT64
,那么 contents[] 数组的类型就是 int64_t,那么 数组的内存长度就是sizeof(int64_t) * length
,数组内数字大小范围为-9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807
整数集合升级
整数集合涉及一个升级问题,比如原本存储的数据都是 int16_t 类型长度的,后面添加了一个 int32_t 长度的数字,那么就需要 先对整个数据结构进行升级,再添加新数字,不过需要注意的是 整数集合不提供降级功能
;升级步骤如下:
- 根据新元素类型,扩展 contents[] 空间大小,并为新元素分配空间
- 将现有 contents[] 里的所有元素数字类型都转换成新元素类型,并将转换后的元素遵循 有序原则放置好
- contents[] 中添加新元素
下面我们就 Redis 整数集合一些 典型的 API 进行解析~~~
源码解析
由于有些方法里的代码量比较大,我们这里按照 典型的代码片段进行解析,同志们可以根据文章提示的代码位置 和 代码里面的关键词 在源码中搜素,可能数据结构一些元素 看不太懂什么意思,没关系,先混个脸熟,后面看完回头再看过来就明白了
数字添加函数 intsetAdd()
上面涉及的 集合升级函数为 intsetUpgradeAndAdd()
另外还有一个在插入操作中很重要的函数,就是 查找插入位置函数 intsetSearch()
另外还有一些 API,不过逻辑比较简单,这里就不一一解读了
intsetRemove()
从整数集合中移除指定元素,O(n)intsetFind()
检查指定值是否存在于集合中,O(log n)intsetRandom()
从整数集合中随机返回一个元素,O(1)intsetGet()
取出给定给定索引上的元素,O(1)intsetLen()
获取整数集合元素个数,O(1)intsetBlobLen()
返回整数集合占用的内存字节数,O(1)
本文作者: wettper
本文链接: http://www.web-lovers.com/redis-source-intset.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!