美文网首页Java互联网科技
redis源码阅读之集合对象

redis源码阅读之集合对象

作者: Java高级架构狮 | 来源:发表于2019-04-18 20:33 被阅读1次

    redis当中集合对象的底层实现为intset和hashtable实现,用hashtable实现时,存储具体值的是key,value统一用NULL。其实集合对象的实现和hash对象的实现还是非常类似的,都是尽可能用占用空间小的底层类型存储,如果实在存不下了,就得鸟枪换炮了
    老规矩,还是先说转换的条件,由于占地较小的实现为intset,这就导致发生转化的条件比
    zipmap->hashtable要不一样了,但也是一共两项,若有一项或一项以上没法满足,则intset转为hashtable:

    1. 集合对象均为整数值;
    2. intset中的元素个数超过512个

    其中第二个限制可以在redis.conf文件中修改

    # set in order to use this special memory saving encoding.
    set-max-intset-entries 512
    

    其转换代码如下:

    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;
            /* Presize the dict to avoid rehashing */
            dictExpand(d,intsetLen(setobj->ptr));
            /* To add the elements we extract integers and create redis objects */
            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");
        }
    }
    

    其中用到转换代码的函数如下所示:

    int setTypeAdd(robj *subject, sds value) {
        long long llval;
        if (subject->encoding == OBJ_ENCODING_HT) {
            /*如果是hashtable,直接加*/
            dict *ht = subject->ptr;
            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) {
            if (isSdsRepresentableAsLonglong(value,&llval) == C_OK) {
                //先判断是否为整数*/
                uint8_t success = 0;
                subject->ptr = intsetAdd(subject->ptr,llval,&success);
                /*插入是否成功*/
                if (success) {
                    /* Convert to regular set when the intset contains
                     * too many entries. */
                    if (intsetLen(subject->ptr) > server.set_max_intset_entries)
                    /*超过阈值*/
                    setTypeConvert(subject,OBJ_ENCODING_HT);
                    return 1;
                }
            } else {
                /*转换类型*/
                /* Failed to get integer from object, convert to regular set. */
                setTypeConvert(subject,OBJ_ENCODING_HT);
                /* The set *was* an intset and this value is not integer
                 * encodable, so dictAdd should always work. */
                serverAssert(dictAdd(subject->ptr,sdsdup(value),NULL) == DICT_OK);
                return 1;
            }
        } else {
            serverPanic("Unknown set encoding");
        }
        return 0;
    }
    

    至于其留给客户端的命令接口,这里也只列出一个,其余不再赘述:

    void saddCommand(client *c) {
        robj *set;
        int j, added = 0;
        set = lookupKeyWrite(c->db,c->argv[1]);
        /*在db中查找指定key*/
        if (set == NULL) {
            /*为空则创建*/
            set = setTypeCreate(c->argv[2]->ptr);
            dbAdd(c->db,c->argv[1],set);
        } else {
            /*不为空则插入*/
            if (set->type != OBJ_SET) {
                /*判断*/
                addReply(c,shared.wrongtypeerr);
                return;
            }
        }
        for (j = 2; j < c->argc; j++) {
            if (setTypeAdd(set,c->argv[j]->ptr)) added++;
        }
        if (added) {
            signalModifiedKey(c->db,c->argv[1]);
            notifyKeyspaceEvent(NOTIFY_SET,"sadd",c->argv[1],c->db->id);
        }
        server.dirty += added;
        addReplyLonglong(c,added);
    }
    

    不足之处还请大家多多指正~~~

    相关文章

      网友评论

        本文标题:redis源码阅读之集合对象

        本文链接:https://www.haomeiwen.com/subject/kblxgqtx.html