整數集合(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
整數數組不支持降級編碼