整数集合(intset)是集合键的底层实现之一,当一个集合含整数元素,而且这个集合的元素数量很少时,Redis就会使用整数集合做为集合键的底层实现。前端
typedef struct intset { // 编码方式 uint32_t encoding; // 集合包含的元素数量 uint32_t length; // 保存元素的数组 int8_t contents[]; } intset;
length记录了元素个数编程
encoding表示当前整数集合的编码方式,可选值有:后端
当添加一个新的数字到整数集合中,而且这个数字长度大于当前的编码方式时,整数集合须要进行升级编码方式,使数组的每个元素都编程新添加数字可以放入最小的编码方式,再将新加元素放入。数组
部分源代码:app
intset *intsetAdd(intset *is, int64_t value, uint8_t *success) { // 计算编码 value 所需的长度 uint8_t valenc = _intsetValueEncoding(value); uint32_t pos; // 默认设置插入为成功 if (success) *success = 1; /* Upgrade encoding if necessary. If we need to upgrade, we know that * this value should be either appended (if > 0) or prepended (if < 0), * because it lies outside the range of existing values. */ // 若是 value 的编码比整数集合如今的编码要大 // 那么表示 value 必然能够添加到整数集合中 // 而且整数集合须要对自身进行升级,才能知足 value 所需的编码 if (valenc > intrev32ifbe(is->encoding)) { /* This always succeeds, so we don't need to curry *success. */ // T = O(N) return intsetUpgradeAndAdd(is,value); } else { ...... } ...... }
intsetUpgradeAndAdd方法源码:ide
static intset *intsetUpgradeAndAdd(intset *is, int64_t value) { .... // 当前的编码方式 uint8_t curenc = intrev32ifbe(is->encoding); // 新值所需的编码方式 uint8_t newenc = _intsetValueEncoding(value); // 当前集合的元素数量 int length = intrev32ifbe(is->length); // 根据 value 的值,决定是将它添加到底层数组的最前端仍是最后端 // 注意,由于 value 的编码比集合原有的其余元素的编码都要大 // 因此 value 要么大于集合中的全部元素,要么小于集合中的全部元素 // 所以,value 只能添加到底层数组的最前端或最后端 int prepend = value < 0 ? 1 : 0; /* First set new encoding and resize */ // 更新集合的编码方式 is->encoding = intrev32ifbe(newenc); // 根据新编码对集合(的底层数组)进行空间调整 // T = O(N) is = intsetResize(is,intrev32ifbe(is->length)+1); while(length--) intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc)); /* Set the value at the beginning or the end. */ // 设置新值,根据 prepend 的值来决定是添加到数组头仍是数组尾 if (prepend) intsetSet(is,0,value); else _intsetSet(is,intrev32ifbe(is->length),value); // 更新整数集合的元素数量 is->length = intrev32ifbe(intrev32ifbe(is->length)+1); return is; }
升级添加大概流程以下:ui
升级的好处:this
整数数组不支持降级编码