Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1851354
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2388
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-21 22:26
个人简介

90后空巢老码农

文章分类

全部博文(184)

文章存档

2021年(26)

2020年(56)

2019年(54)

2018年(47)

2017年(1)

我的朋友

分类: NOSQL

2019-04-16 19:37:17

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

点击(此处)折叠或打开

  1. # set in order to use this special memory saving encoding.
  2. set-max-intset-entries 512
其转换代码如下:

点击(此处)折叠或打开

  1. void setTypeConvert(robj *setobj, int enc) {
  2.     setTypeIterator *si;
  3.     serverAssertWithInfo(NULL,setobj,setobj->type == OBJ_SET &&
  4.                              setobj->encoding == OBJ_ENCODING_INTSET);

  5.     if (enc == OBJ_ENCODING_HT) {
  6.         int64_t intele;
  7.         dict *d = dictCreate(&setDictType,NULL);
  8.         sds element;

  9.         /* Presize the dict to avoid rehashing */
  10.         dictExpand(d,intsetLen(setobj->ptr));

  11.         /* To add the elements we extract integers and create redis objects */
  12.         si = setTypeInitIterator(setobj);
  13.         while (setTypeNext(si,&element,&intele) != -1) {
  14.             element = sdsfromlonglong(intele);
  15.             serverAssert(dictAdd(d,element,NULL) == DICT_OK);
  16.         }
  17.         setTypeReleaseIterator(si);

  18.         setobj->encoding = OBJ_ENCODING_HT;
  19.         zfree(setobj->ptr);
  20.         setobj->ptr = d;
  21.     } else {
  22.         serverPanic("Unsupported set conversion");
  23.     }
  24. }
其中用到转换代码的函数如下所示:

点击(此处)折叠或打开

  1. int setTypeAdd(robj *subject, sds value) {
  2.     long long llval;
  3.     if (subject->encoding == OBJ_ENCODING_HT) {/*如果是hashtable,直接加*/
  4.         dict *ht = subject->ptr;
  5.         dictEntry *de = dictAddRaw(ht,value,NULL);
  6.         if (de) {
  7.             dictSetKey(ht,de,sdsdup(value));
  8.             dictSetVal(ht,de,NULL);
  9.             return 1;
  10.         }
  11.     } else if (subject->encoding == OBJ_ENCODING_INTSET) {
  12.         if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) {//先判断是否为整数*/
  13.             uint8_t success = 0;
  14.             subject->ptr = intsetAdd(subject->ptr,llval,&success);/*插入是否成功*/
  15.             if (success) {
  16.                 /* Convert to regular set when the intset contains
  17.                  * too many entries. */
  18.                 if (intsetLen(subject->ptr) > server.set_max_intset_entries)/*超过阈值*/
  19.                     setTypeConvert(subject,OBJ_ENCODING_HT);
  20.                 return 1;
  21.             }
  22.         } else {/*转换类型*/
  23.             /* Failed to get integer from object, convert to regular set. */
  24.             setTypeConvert(subject,OBJ_ENCODING_HT);

  25.             /* The set *was* an intset and this value is not integer
  26.              * encodable, so dictAdd should always work. */
  27.             serverAssert(dictAdd(subject->ptr,sdsdup(value),NULL) == DICT_OK);
  28.             return 1;
  29.         }
  30.     } else {
  31.         serverPanic("Unknown set encoding");
  32.     }
  33.     return 0;
  34. }
至于其留给客户端的命令接口,这里也只列出一个,其余不再赘述:


点击(此处)折叠或打开

  1. void saddCommand(client *c) {
  2.     robj *set;
  3.     int j, added = 0;

  4.     set = lookupKeyWrite(c->db,c->argv[1]);/*在db中查找指定key*/
  5.     if (set == NULL) {/*为空则创建*/
  6.         set = setTypeCreate(c->argv[2]->ptr);
  7.         dbAdd(c->db,c->argv[1],set);
  8.     } else {/*不为空则插入*/
  9.         if (set->type != OBJ_SET) {/*判断*/
  10.             addReply(c,shared.wrongtypeerr);
  11.             return;
  12.         }
  13.     }

  14.     for (j = 2; j < c->argc; j++) {
  15.         if (setTypeAdd(set,c->argv[j]->ptr)) added++;
  16.     }
  17.     if (added) {
  18.         signalModifiedKey(c->db,c->argv[1]);
  19.         notifyKeyspaceEvent(NOTIFY_SET,"sadd",c->argv[1],c->db->id);
  20.     }
  21.     server.dirty += added;
  22.     addReplyLongLong(c,added);
  23. }

不足之处还请大家多多指正~~~
阅读(6789) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~