redis数据结构之整数集合

本文介绍了Redis中整数集合的内部实现,当插入不同大小的整数时,集合会自动升级以保持所有元素的编码类型一致。升级过程中,原有的元素会被转换为新的编码类型,然后添加新元素。升级操作通过intsetUpgradeAndAdd函数完成,并涉及内存的重新分配。由于整数集合是有序的,因此Redis使用二分查找进行搜索。
摘要由CSDN通过智能技术生成

redis的整数集合实质上是动态的数组。reids的整数集合是可以根据整数的值,自动选择用什么长度来存储的。例如:如果插入的值可以用int16_t类型来保存,那所有的元素都可以用int16_t类型来保存。所以可以看出保存的类型应该有这几种:

#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))

其实还有种int8_t,但是redis在创建整数集合的时候就默认最小使用int16_t,所以int8_t就是一个保留的类型。下面来看下整数集合的定义:

typedef struct intset {

    // 保存元素所使用的类型的长度
    uint32_t encoding;

    // 元素个数
    uint32_t length;    

    // 保存元素的数组
    int8_t contents[];  

} intset;
encoding就是上面说的类型;

有人对对contents的类型为int8_t 有疑惑:下面截取redis设计和实现这本书里的一段话来进行解释:

contents 数组的int8_t 类型声明比较容易让人误解,实际上,intset 并不使用int8_t 类型来保存任何元素,结构中的这个类型声明只是作为一个占位符使用:在对contents 中的元素进行读取或者写入时,程序并不是直接使用contents 来对元素进行索引,而是根据encoding的值,对contents 进行类型转换和指针运算,计算出元素在内存中的正确位置。在添加新元素,进行内存分配时,分配的容量也是由encoding 的值决定。

下面用具体的代码来进行解释下:

static int64_t _intsetGetEncoded(intset *is, int pos, uint8_t enc) {
    int64_t v64;
    int32_t v32;
    int16_t v16;

    if (enc == INTSET_ENC_INT64) {
        memcpy(&v64,((int64_t*)is->contents)+pos,sizeof(v64));
        memrev64ifbe(&v64);
        return v64;
    } else if (enc == INTSET_ENC_INT32) {
        memcpy(&v32,((int32_t*)is->contents)+pos,sizeof(v32));
        memrev32ifbe(&v32);
        return v32;
    } else {
        memcpy(&v16,((int16_t*)is->contents)+pos,sizeof(v16));
        memrev16ifbe(&v16);
        return v16;
    }
}

上面的函数就是获取整数集合的某个整数,可以看出获取整数前都是把content的类型转换成相应的encode类型,再通过encode类型和整数在整数集合中的位置(pos)找到内存中地址,再拷贝过来。

整数集合中的encode类型必须一致,也就是说如果新插入的值的类型比较大的话会自动升级到相应的encode类型。例如:新元素的长度为int32_t ,那么这个intset 就会自动进行“升级” :先将集合中现有的所有元素从int16_t 类型转换为int32_t 类型,接着再将新元素加入到集合中。

根据需要,intset 可以自动从int16_t 升级到int32_t 或int64_t ,或者从int32_t 升级到int64_t 。

整数集合的升级是通过intsetUpgradeAndAdd这个函数来进行升级。这个函数最主要的一部分如下:

    while(length--)
        _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));
这个就是把原先整数集合中的类型升级到现在的类型,升级的示意图如下:

在升级之前,内存示意图如下:

重新分配空间后的内存示意图:

升级过程的内存示意图:

上面就是整个升级的过程。

注意:整数集合是一个有序的集合,所以redis搜索的时候采用的是二分查找。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值