Redis Intset(整数集合)技术文档

Redis Intset(整数集合)技术文档

一、概述

Intset(整数集合)是 Redis 中Set 数据类型的底层编码之一 ,用于存储整数集合。当 Set 中的元素都是整数且数量较少时,Redis 会使用 Intset 作为底层实现。

1.1 设计思想

"用最小的空间存储整数,自动升级编码以适应更大的整数"

1.2 使用场景

  • Set 类型:当所有元素都是整数且数量较少时
  • 元素范围:取决于编码(int16/int32/int64)

二、数据结构

c 复制代码
typedef struct intset {
    uint32_t encoding;    // 编码类型
    uint32_t length;      // 元素数量
    int8_t contents[];    // 柔性数组,存储实际数据
} intset;

2.1 内存布局

scss 复制代码
+-----------+-----------+---------------------------+
| encoding  |  length   |      contents[]           |
| (4 bytes) | (4 bytes) | (length * encoding bytes) |
+-----------+-----------+---------------------------+
字段 类型 说明
encoding uint32_t 元素编码(INT16/INT32/INT64)
length uint32_t 元素数量
contents int8_t[] 实际存储的数据(柔性数组)

2.2 编码类型

c 复制代码
#define INTSET_ENC_INT16 (sizeof(int16_t))  // 2 bytes
#define INTSET_ENC_INT32 (sizeof(int32_t))  // 4 bytes
#define INTSET_ENC_INT64 (sizeof(int64_t))  // 8 bytes
编码 大小 范围
INTSET_ENC_INT16 2 bytes -32768 ~ 32767
INTSET_ENC_INT32 4 bytes -2^31 ~ 2^31-1
INTSET_ENC_INT64 8 bytes -2^63 ~ 2^63-1

三、核心特性

3.1 有序存储

Intset 中的元素按升序排列 ,支持二分查找

diff 复制代码
+---+---+---+---+---+---+
| 1 | 3 | 5 | 7 | 9 | 11|
+---+---+---+---+---+---+

3.2 自动升级

当插入一个超出当前编码范围的整数时,Intset 会自动升级编码:

sql 复制代码
Before: INT16 encoding
+-----+-----+-----+
| 100 | 200 | 300 |
+-----+-----+-----+

Insert: 40000 (超出 INT16 范围)

After: INT32 encoding (自动升级)
+-----+-----+-----+-----+
| 100 | 200 | 300 |40000|
+-----+-----+-----+-----+

升级过程

  1. 重新分配内存(新编码大小 × 元素数)
  2. 从后向前复制数据(避免覆盖)
  3. 插入新元素

3.3 不重复

Intset 保证元素不重复,插入时会先查找。


四、核心 API

4.1 创建与销毁

c 复制代码
intset *intsetNew(void);   // 创建空 intset

4.2 插入与删除

c 复制代码
// 插入元素(自动去重)
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);

// 删除元素
intset *intsetRemove(intset *is, int64_t value, int *success);

4.3 查询操作

c 复制代码
// 查找元素
uint8_t intsetFind(intset *is, int64_t value);

// 获取指定位置的值
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value);

// 获取随机值
int64_t intsetRandom(intset *is);

// 获取最大值
int64_t intsetMax(intset *is);

// 获取最小值
int64_t intsetMin(intset *is);

// 获取长度
uint32_t intsetLen(const intset *is);

五、核心算法

5.1 二分查找

c 复制代码
static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
    int min = 0, max = intrev32ifbe(is->length) - 1, mid = -1;
    int64_t cur = -1;

    // 边界情况
    if (intrev32ifbe(is->length) == 0) {
        if (pos) *pos = 0;
        return 0;
    }

    if (value > _intsetGet(is, max)) {
        if (pos) *pos = intrev32ifbe(is->length);
        return 0;
    } else if (value < _intsetGet(is, 0)) {
        if (pos) *pos = 0;
        return 0;
    }

    // 二分查找
    while (max >= min) {
        mid = ((unsigned int)min + (unsigned int)max) >> 1;
        cur = _intsetGet(is, mid);
        if (value > cur) {
            min = mid + 1;
        } else if (value < cur) {
            max = mid - 1;
        } else {
            break;
        }
    }

    if (value == cur) {
        if (pos) *pos = mid;
        return 1;  // 找到
    } else {
        if (pos) *pos = min;
        return 0;  // 未找到
    }
}

5.2 编码升级

c 复制代码
static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
    uint8_t curenc = intrev32ifbe(is->encoding);
    uint8_t newenc = _intsetValueEncoding(value);
    int length = intrev32ifbe(is->length);
    int prepend = value < 0 ? 1 : 0;

    // 设置新编码并扩容
    is->encoding = intrev32ifbe(newenc);
    is = intsetResize(is, intrev32ifbe(is->length) + 1);

    // 从后向前复制(避免覆盖)
    while (length--) {
        _intsetSet(is, length + prepend, 
                   _intsetGetEncoded(is, length, curenc));
    }

    // 插入新值
    if (prepend) {
        _intsetSet(is, 0, value);
    } else {
        _intsetSet(is, intrev32ifbe(is->length), value);
    }
    is->length = intrev32ifbe(intrev32ifbe(is->length) + 1);
    return is;
}

六、性能分析

操作 复杂度 说明
查找 O(log n) 二分查找
插入 O(n) 插入位置后移 + 可能升级
删除 O(n) 删除位置前移
获取长度 O(1) 直接读取
获取最大/小值 O(1) 首尾元素

七、在 Redis 中的应用

c 复制代码
// 当 Set 满足以下条件时使用 Intset:
// 1. 所有元素都是整数
// 2. 元素数量 < set-max-intset-entries (默认 512)

// 配置
set-max-intset-entries 512

参考源码 :Redis 8.8.2 (src/intset.h, src/intset.c)

相关推荐
01传说1 小时前
redis开机自启脚本
数据库·redis·缓存
只爱喝胡辣汤3 小时前
Redis SDS(Simple Dynamic String)技术文档
redis
只爱喝胡辣汤4 小时前
Redis Dict(字典/哈希表)技术文档
redis
就叫_这个吧6 小时前
RabbitMQ+elasticsearch+Redis,实现新增内容并异步到es中,是否消费成功检测
redis·elasticsearch·rabbitmq
李可以量化6 小时前
Redis Client 从了解到精通(二)下:String 类型进阶操作全解
redis·git·python·量化交易·qmt
BUG研究员_7 小时前
LangChain 向量数据库实战:Redis 与 Pinecone 的知识点总结
数据库·redis·langchain
李可以量化8 小时前
Redis Client 从了解到精通(二)上:redis-py 高级用法与核心命令实战
前端·数据库·redis·python·缓存·ptrade
仍然.8 小时前
Redis---String
数据库·redis·缓存
JavaPub-rodert9 小时前
Redis 和 MySQL 如何保证数据一致性?从缓存更新到延迟双删完整讲解
redis·mysql·缓存