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_tint32_t或者int64_t类型的数据。

contents数组保存的数据类型与encoding属性是相互关联的,其对应关系如下表格:

contents[]encoding
int16_tINTSET_ENC_INT16
int32_tINTSET_ENC_INT32
int64_tINTSET_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位
元素123

根据新元素的类型扩展数组的空间
新添加的元素的类型为32位的整型,故一共需要的空间为(length+1)*32=4*32=127
分配完后的结构如下

0-15位16-31位32-47位48-127位
元素123新分配的空间

将其他的数据类型转化为与新元素的数据类型相同
按照从大到小的顺序,将numbers集合中元素的类型进行转换

首先是元素3,在所有元素中是第三小的,故将其移动到contents[2]的位置上

0-15位16-31位32-47位48-63位64-95位96-127位
元素12-新分配的空间3新分配的空间

接下来是2,在所有元素中是第二小的,故将其移动到contents[1]的位置上

0-15位16-31位32-63位64-95位96-127位
元素1-23新分配的空间

最后是1,在所有元素中是第一小的,故将其移动到contents[0]的位置上

0-31位32-63位64-95位96-127位
元素123新分配的空间

将新元素插入到数据的合适位置,并更新encoding属性的值

0-31位32-63位64-95位96-127位
元素12365535

最后将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)

Redis 整数集合

快速整明白Redis中的整数集合到底是个啥

Redis实现之对象

Redis源码剖析 - Reids内置数据结构之整数集合intset

Redis源码剖析 - Reids内置数据结构之整数集合intset