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. 節約內存

整數數組不支持降級編碼

相關文章
相關標籤/搜索