Redis深度歷險-集合 Redis深度歷險-集合

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");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章