Redis 整数集合

整数集合(intset)是集合键的底层实现之一,当一个集合含整数元素,而且这个集合的元素数量很少时,Redis就会使用整数集合做为集合键的底层实现。前端

intset.h/intset源码

typedef struct intset {
  
  // 编码方式
  uint32_t encoding;

  // 集合包含的元素数量
  uint32_t length;

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

} intset;

length记录了元素个数编程

encoding表示当前整数集合的编码方式,可选值有:后端

  1. INTSET_ENC_INT16 表示当前元素都是16位的数字编码,即每一个元素使用contents素组的2个数组单位存储
  2. INTSET_ENC_INT32 表示当前元素都是32位的数字编码,即每一个元素使用contents素组的4个数组单位存储
  3. INTSET_ENC_INT64 表示当前元素都是64位的数字编码,即每一个元素使用contents素组的8个数组单位存储

 

升级

当添加一个新的数字到整数集合中,而且这个数字长度大于当前的编码方式时,整数集合须要进行升级编码方式,使数组的每个元素都编程新添加数字可以放入最小的编码方式,再将新加元素放入。数组

部分源代码: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

  1. 根据新值须要的编码方式扩展当前数组长度
  2. 将旧值根据老的编码方式和新的编码方式从新编码并移动到正确位置
  3. 插入新值

升级的好处:this

  1. 灵活,能够根据最长数字灵活调整统一整个数组的编码
  2. 节约内存

整数数组不支持降级编码

相关文章
相关标签/搜索