前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从源码看redis的'set'结构

从源码看redis的'set'结构

作者头像
爬蜥
发布2020-03-20 12:46:31
3360
发布2020-03-20 12:46:31
举报

sadd 命令用来往 set 结构中存入数据

> sadd a 1
(integer) 1
复制代码

smembers可以查到存储的内容

> smembers a
1) "1"
复制代码

sadd命令执行追踪

sadd的执行入口在 saddCommand,如果key不存在那么第一件事情就是确认底层的存储结构

 Code.SLICE.source("robj *setTypeCreate(sds value) {" +
      "    if (isSdsRepresentableAsLongLong(value,NULL) == C_OK)" +
      "        return createIntsetObject();" +
      "    return createSetObject();" +
      "}")
      .interpretation("看set中要添加的值是否能够转成long long类型,如果可以,set的类型为IntSet,否则使用hash table");
复制代码

确定好结构之后,可以往里面去增加

  • 如果原本是 hashtable,那么直接插入即可;
  • 如果原本是intset,则需要看新插入的元素是否满足intset的结构,否则转成hashtable存储
Code.SLICE.source("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;" +
        "        }" +
        "    }")
        .interpretation("set的另外一种数据结构,intset ,只要当前数据还能够转换成 longlong,那么继续在set中增加,否则将结构转换成 hashtable")
        .interpretation("1: 往intset添加成功之后,如果集合的元素个数已经超过了 配置的 set_max_intset_entries ,那么转换成 hashtable");
复制代码

在往intset中插入的时候,需要确保不存存储一样的元素,因此会先查找是否有一样值的元素

Code.SLICE.source("int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;")
        .interpretation("先记下最小值和最大值的下标");
Code.SLICE.source("  if (intrev32ifbe(is->length) == 0) {" +
        "        if (pos) *pos = 0;" +
        "        return 0;" +
        "    } else {" +
        "        /* Check for the case where we know we cannot find the value," +
        "         * but do know the insert position. */" +
        "        if (value > _intsetGet(is,intrev32ifbe(is->length)-1)) {" +
        "            if (pos) *pos = intrev32ifbe(is->length);" +
        "            return 0;" +
        "        } else if (value < _intsetGet(is,0)) {" +
        "            if (pos) *pos = 0;" +
        "            return 0;" +
        "        }" +
        "    }")
        .interpretation("处理边界情况")
        .interpretation("1: 如果集合中是空的,直接在开始插入即可")
        .interpretation("2: 如果新插入的值小于当前最小的值,在开头插入即可")
        .interpretation("3: 如果插入新值大于当前最大的值,在结尾插入即可");
Code.SLICE.source("while(max >= min) {" +
        "        mid = ((unsigned int)min + (unsigned int)max) >> 1;" +
        "        cur = _intsetGet(is,mid);" +
        "        if (value > cur) {" +
        "            min = mid+1;" +
        "        } else if (value < cur) {" +
        "            max = mid-1;" +
        "        } else {" +
        "            break;" +
        "        }" +
        "    }")
        .interpretation("二分查找,找到插入的位置,这里要么找到现有值元素的位置,要么找到要插入的位置");
复制代码

总结

  1. set 底层使用了两种结构 intset和hashtable ;
  2. intset 内部是按照升序排列;
  3. intset根据数值大小会分成不同的数据结构,方便节省空间

附录

sadd命令源码完整的追踪过程

Redis开发与运维

Redis的设计与实现

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年03月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • sadd命令执行追踪
  • 总结
  • 附录
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档