美文网首页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源码阅读之集合对象

    redis当中集合对象的底层实现为intset和hashtable实现,用hashtable实现时,存储具体值的是...

  • 再探Redis对象与底层数据结构的关系

    大纲:简述Redis五种对象所使用的的底层数据结构 字符串对象 列表对象 哈希对象 集合对象 有序集合对象 阅读本...

  • redis中的对象

    redis的对象包含5种对象: 字符串对象 列表对象 哈希对象 集合对象 有序集合对象 redis对象的好处 针对...

  • iOS 系统源码及第三方源码总结

    1.系统源码总结 RunTime源码阅读(一)之weakRunTime源码阅读(二)关联对象RunTime源码阅读...

  • Redis对象类型及应用

    Redis数据对象类型  Redis共有五种数据对象,包括:字符串、列表、hash表、集合、有序集合。每种对象都至...

  • 面试题|Java|Redis

    Redis内存模型 Redis内存分配 数据 :Redis存储的数据对象 字符串、哈希、列表、集合、有序集合 进程...

  • Redis笔记之集合对象

    集合对象的编码可以是intset或者字典。 对象中不同类型的适用条件: 只有同时满足以下两个条件时才会使用ints...

  • redis集合对象

    内容来自:《redis设计与实现》购买本书请访问: 京东商城《Redis 深度历险:核心原理与应用实践》购买本书请...

  • Redis 集合对象

    集合对象的编码可以是 intset 或者 hashtable intset 编码的集合对象使用整数集合作为底层实现...

  • redis数据结构--对象

    redis使用对象系统来构建键值对数据库,这个对象系统包括:字符串对象,列表对象,哈希对象,集合对象和有序集合对象...

网友评论

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

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