1丶什么是intset
Redis 中的 intset(整数集合)是一种高效的数据结构选择。Intset 具有紧凑的内存布局和快速的插入、删除和查找操作,适用于存储大量整数,并且能够节省内存空间。
2丶先说优点
内存布局:Intset 的内存布局非常紧凑。它使用连续的内存块存储整数,并且根据实际存储的整数大小选择适当的编码方式,以节省内存空间。
编码方式:Intset 使用不同的编码方式来存储整数,包括 INT16、INT32 和 INT64。它根据存储的整数值的范围选择最小的编码方式,以便节省内存。编码方式会根据需要进行动态调整。
快速的查找: 因为intset是有序数组,支持logn的查找复杂度. 2分大法.
3丶局限性
Intset 只能存储整数类型的数据,不支持其他数据类型。
频繁的插入和删除 中间元素; 不是最小最大元素.
4丶个人理解的使用场景
1丶整数. 2丶增删改 比较少.(或者插入有序的整数) 3丶主要用于查询 4丶空间资源紧缺
默认在512长度的整数内是使用该结构的,看读者的需求,如果是大量整数的存储且主要用于查询,可以调大这个配置.
redis.config中配置: set-max-intset-entries = 你需要的
5丶源码分析
1丶先看头文件.
###丶2丶点进创建的方法.
这个没啥难度,就是初始化,分配内存,设置默认值.此时可以知道,他默认内存只是 encoding字段和length字段占用的空间大小.所以比dict结构省很多空间,键值对啊?扩展保留的空间啊,等等.
intset *intsetNew(void) {
//分配内存
intset *is = zmalloc(sizeof(intset));
//指定编码方式; 默认使用了 INTSET_ENC_INT16; 即有符号的
is->encoding = intrev32ifbe(INTSET_ENC_INT16);
is->length = 0;
return is;
}
3丶插入方法
intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
//拿到当前元素的编码方式;方法直接放这里了,省的看.就是一些常量的大小比较.
// static uint8_t _intsetValueEncoding(int64_t v) {
// if (v < INT32_MIN || v > INT32_MAX)
// return INTSET_ENC_INT64;
// else if (v < INT16_MIN || v > INT16_MAX)
// return INTSET_ENC_INT32;
// else
// return INTSET_ENC_INT16;
// }
uint8_t valenc = _intsetValueEncoding(value);
//插入的位置.position
uint32_t pos;
if (success) *success = 1;
//如果插入的大于
if (valenc > intrev32ifbe(is->encoding)) {
/* This always succeeds, so we don't need to curry *success. */
return intsetUpgradeAndAdd(is,value);
} else {
/* Abort if the value is already present in the set.
* This call will populate "pos" with the right position to insert
* the value when it cannot be found. */
if (intsetSearch(is,value,&pos)) {
if (success) *success = 0;
return is;
}
is = intsetResize(is,intrev32ifbe(is->length)+1);
if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
}
_intsetSet(is,pos,value);
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
return is;
}
暂定后续更新