Redis深度歷險-集合
Redis中的set是一種無序集合,如果存儲的全部都是數字則內部使用的是intset存儲,否則使用的是hashtab存儲
字符串集合
int setTypeAdd(robj *subject, sds value) {
long long llval;
if (subject->encoding == OBJ_ENCODING_HT) {
dict *ht = subject->ptr;
//使用的是字典存儲,只不過value是NULL
dictEntry *de = dictAddRaw(ht,value,NULL);
if (de) {
dictSetKey(ht,de,sdsdup(value));
dictSetVal(ht,de,NULL);
return 1;
}
} else if (subject->encoding == OBJ_ENCODING_INTSET) {
..........
} else {
serverPanic("Unknown set encoding");
}
return 0;
}
在編碼是OBJ_ENCODING_HT
時直接使用字典來存儲,只不過所有的value是NULL
數字集合
int setTypeAdd(robj *subject, sds value) {
long long llval;
if (subject->encoding == OBJ_ENCODING_HT) {
.........
} else if (subject->encoding == OBJ_ENCODING_INTSET) {
//判斷能夠轉爲long long類型的證書
if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) {
uint8_t success = 0;
//插入到intset數據結構中
subject->ptr = intsetAdd(subject->ptr,llval,&success);
if (success) {
//如果intset中存儲的數據超過set_max_intset_entries則轉爲字典存儲,默認512個
if (intsetLen(subject->ptr) > server.set_max_intset_entries)
setTypeConvert(subject,OBJ_ENCODING_HT);
return 1;
}
} else {
//不能轉換成證書,則轉爲存儲到字典中
setTypeConvert(subject,OBJ_ENCODING_HT);
serverAssert(dictAdd(subject->ptr,sdsdup(value),NULL) == DICT_OK);
return 1;
}
} else {
serverPanic("Unknown set encoding");
}
return 0;
}
編碼類型轉換
在插入字符串或者數據數量超過512個(配置文件中設置)時轉爲爲
OBJ_ENCODING_HT
void setTypeConvert(robj *setobj, int enc) {
setTypeIterator *si;
serverAssertWithInfo(NULL,setobj,setobj->type == OBJ_SET &&
setobj->encoding == OBJ_ENCODING_INTSET);
//只支持轉換爲字典類型
if (enc == OBJ_ENCODING_HT) {
int64_t intele;
dict *d = dictCreate(&setDictType,NULL);
sds element;
//按集合數據類型,初始化字典空間
dictExpand(d,intsetLen(setobj->ptr));
//將intset中的每一項數據逐個加入到集合中
si = setTypeInitIterator(setobj);
while (setTypeNext(si,&element,&intele) != -1) {
element = sdsfromlonglong(intele);
serverAssert(dictAdd(d,element,NULL) == DICT_OK);
}
setTypeReleaseIterator(si);
//釋放原油的空間
setobj->encoding = OBJ_ENCODING_HT;
zfree(setobj->ptr);
setobj->ptr = d;
} else {
serverPanic("Unsupported set conversion");
}
}