Redis整数集合(intset)的升级操作
Posted 十木禾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis整数集合(intset)的升级操作相关的知识,希望对你有一定的参考价值。
当Redis
中的Set(集合)只存有整数值元素的时候,并且元素的数目并不是非常多的时候,就会使用intset(整数集合)作为集合键的底层实现。
127.0.0.1:6381> SADD numbers 2 4 6
(integer) 3
127.0.0.1:6381> OBJECT ENCODING numbers
"intset"
通过上面的代码我们就知道集合numbers
的存储结构是intset
。
那么这个整数集合是怎么样实现的呢,我们来看一下其源码:
typedef struct intset
/* 编码方式 */
uint32_t encoding;
/* 集合包含的元素数量 */
uint32_t length;
/* 保存元素的数组 */
int8_t contents[];
intset;
虽然数组contents
数组的类型为int8_t
,但是其并不会保存任何int8_t
类型的数据,其会保存int16_t
,int32_t
或者int64_t
类型的数据。
contents
数组保存的数据类型与encoding
属性是相互关联的,其对应关系如下表格:
contents[] | encoding |
---|---|
int16_t | INTSET_ENC_INT16 |
int32_t | INTSET_ENC_INT32 |
int64_t | INTSET_ENC_INT64 |
该博客讲的是intset
的升级操作,这里简单解释一下什么是升级操作
为了节约内存,如果intset
存储的数据可以用16位的整数(-32768~32767)表示,那么contents
数据的类型就会被设置为int16_t
,如果这个时候被添加进来一个大于32767的,比如说为65535,int16_t
就存储不下了,这个时候就需要升级操作,将contents
数据的类型就会被设置为int32_t
。——这个过程就是升级的过程。
升级intset
并添加新元素的过程分为以下三步
- 根据新元素的类型扩展数组的空间
- 将其他的数据类型转化为与新元素的数据类型相同
- 将新元素插入到数据的合适位置,并更新
encoding
属性的值
接下来图示如下过程
127.0.0.1:6381> SADD numbers 1 2 3
(integer) 3
127.0.0.1:6381> SADD numbers 65535
(integer) 1
我们知道再numbers
中插入65535
的时候就需要经行升级操作了,其过程的图示如下
SADD numbers 1 2 3
操作后,其intset
的结构如下
contents
数组的各个元素的位置如下
位 | 0-15位 | 16-31位 | 32-47位 |
---|---|---|---|
元素 | 1 | 2 | 3 |
根据新元素的类型扩展数组的空间
新添加的元素的类型为32位的整型,故一共需要的空间为(length+1)*32=4*32=127
分配完后的结构如下
位 | 0-15位 | 16-31位 | 32-47位 | 48-127位 |
---|---|---|---|---|
元素 | 1 | 2 | 3 | 新分配的空间 |
将其他的数据类型转化为与新元素的数据类型相同
按照从大到小的顺序,将numbers
集合中元素的类型进行转换
首先是元素3,在所有元素中是第三小的,故将其移动到contents[2]
的位置上
位 | 0-15位 | 16-31位 | 32-47位 | 48-63位 | 64-95位 | 96-127位 |
---|---|---|---|---|---|---|
元素 | 1 | 2 | - | 新分配的空间 | 3 | 新分配的空间 |
接下来是2,在所有元素中是第二小的,故将其移动到contents[1]
的位置上
位 | 0-15位 | 16-31位 | 32-63位 | 64-95位 | 96-127位 |
---|---|---|---|---|---|
元素 | 1 | - | 2 | 3 | 新分配的空间 |
最后是1,在所有元素中是第一小的,故将其移动到contents[0]
的位置上
位 | 0-31位 | 32-63位 | 64-95位 | 96-127位 |
---|---|---|---|---|
元素 | 1 | 2 | 3 | 新分配的空间 |
将新元素插入到数据的合适位置,并更新encoding
属性的值
位 | 0-31位 | 32-63位 | 64-95位 | 96-127位 |
---|---|---|---|---|
元素 | 1 | 2 | 3 | 65535 |
最后将encoding
属性的值更新为INTSET_ENC_INT32
,将length
的值加一。
完成上述的操作之后,现在intset
的结构如下
升级操作带来好处是增加了数组操作的灵活性并且能够达到节约内存的效果。
与升级操作相对应的是降级操作,但是intset
是没有提供降级操作的功能的,这就是说对上面的numbers
执行操作
127.0.0.1:6381> SREM numbers 65535
(integer) 1
其他的三个元素(1,2,3)的数据类型仍然还是int32_t
,并不会因此而降级为int16_t
以上是关于Redis整数集合(intset)的升级操作的主要内容,如果未能解决你的问题,请参考以下文章
Redis 设计与实现(第六章) -- 整数集合(intset)