本文所引用的源码全部来自Redis2.8.2版本。
REDIS_SET集合数据类型与指令相关文件是t_set.h, redis.h, object.c转载请注明,文章出自:http://blog.csdn.net/acceptedxukai/article/details/17883153
集合编码方式
Redis 集合(set)使用REDIS_ENCONDING_INT与REDIS_ENCONDING_HT两种编码方式
1、REDIS_ENCONDING_INT: intset.c/intset.h
2、REDIS_ENCONDING_HT: dict.c/dict.h
第一个添加到集合的元素,决定了创建集合时所使用的编码:如果第一个元素可以表示为 long long 类型值(也即是,它是一个整数),那么集合的初始编码为 REDIS_ENCODING_INTSET ;否则,集合的初始编码为 REDIS_ENCODING_HT 。
编码切换:如果一个集合使用 REDIS_ENCODING_INTSET 编码,那么当以下任何一个条件被满足时,这个集合会被转换成 REDIS_ENCODING_HT 编码:
1、 intset 保存的整数值个数超过 server.set_max_intset_entries (默认值为 512 )
2、试图往集合里添加一个新元素,并且这个元素不能被表示为 long long 类型
集合指令实现
SADD
指令格式: SADD key member [member...]
将一个或多个member元素加入到集合key当中,由于集合成员不能重复,已经存在于集合key中的member元素将被忽略。
如果key不存在,则创建一个包含被添加的member元素的新集合。
如果key不是集合类型(REDIS_SET)时,则操作出错,redis返回一个错误。
时间复杂度:O(N)
void saddCommand(redisClient *c) { robj *set; int j, added = 0; set = lookupKeyWrite(c->db,c->argv[1]);//写查找数据库中名为c->argv[1]的集合 if (set == NULL) {//集合不存在 set = setTypeCreate(c->argv[2]);//创建一个新的集合 dbAdd(c->db,c->argv[1],set);//将该集合添加到数据库中,dict中的key就是集合的名称,value就是集合元素 } else { if (set->type != REDIS_SET) {//判断是否是集合类型 addReply(c,shared.wrongtypeerr); return; } } for (j = 2; j < c->argc; j++) {//添加集合元素 c->argv[j] = tryObjectEncoding(c->argv[j]);//尝试使用整型存储数据 if (setTypeAdd(set,c->argv[j])) added++; } if (added) { signalModifiedKey(c->db,c->argv[1]);//通知数据库哪些键key变化了,把变化的key存储到watched_keys中,只在事务操作时才用的着 notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[1],c->db->id);//暂不知道啥用途 } server.dirty += added;//数据库中数据变化的数目 addReplyLongLong(c,added); }
lookupKeyWrite函数在object.c文件中,用来在数据库中查找指定key的value值。
setTypeCreate函数在创建一个新的Redis_Set时,根据添加的元素类型为整型还是字符串会创建不同的存储数据结构
//创建一个集合对象,如果value是整型,那么使用intset,否则使用dict robj *setTypeCreate(robj *value) { if (isObjectRepresentableAsLongLong(value,NULL) == REDIS_OK) return createIntsetObject();//intset return createSetObject();//dict } robj *createSetObject(void) { dict *d = dictCreate(&setDictType,NULL); robj *o = createObject(REDIS_SET,d); o->encoding = REDIS_ENCODING_HT; return o; } robj *createIntsetObject(void) { intset *is = intsetNew(); robj *o = createObject(REDIS_SET,is); o->encoding = REDIS_ENCODING_INTSET; return o; } robj *createObject(int type, void *ptr) { robj *o = zmalloc(sizeof(*o)); o->type = type; o->encoding = REDIS_ENCODING_RAW; o->ptr = ptr; o->refcount = 1; /* Set the LRU to the current lruclock (minutes resolution). */ o->lru = server.lruclock; return o; }
SCARD
SCARD key
返回集合key中元素的个数
时间复杂度:O(1)
简单根据集合的编码类型:如果是HT编码,那么直接通过dictSize函数得到字典中元素的个数;如果是intset编码,那么直接通过intsetLen函数得到结果.
SISMEMBER
SISMEMBER key member
判断member元素是否集合key的中的元素
时间复杂度: O(1)
简单根据集合的编码类型:如果是HT编码,那么直接通过dictFind函数查找字典中是否存在该member;如果是intset编码,那么直接通过intsetFind函数查找是否存在该member.
SMEMBERS
SMEMBERS key
返回集合key中的所有元素,不存在的key被视为空集合。
时
Redis数据类型与指令详解之集合(t_set)
最新推荐文章于 2024-07-06 03:29:00 发布
本文详细介绍了Redis中集合的数据编码方式,包括INTSET和HT,并解析了SADD、SCARD、SISMEMBER等集合指令的实现。同时,探讨了集合的交、差、并算法及其时间复杂度,最后对集合操作进行了总结。
摘要由CSDN通过智能技术生成