Redis整数集合(intset)的升级操作

版权声明:转载请注明出处! https://blog.csdn.net/zjq_1314520/article/details/79039582

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_tint32_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并添加新元素的过程分为以下三步

  1. 根据新元素的类型扩展数组的空间
  2. 将其他的数据类型转化为与新元素的数据类型相同
  3. 将新元素插入到数据的合适位置,并更新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

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页