1 sismemberCommand
1.1 方法说明
??判断一个值是否属于集合的成员,成功返回1,失败返回0。
1.2 命令实践
1.3 方法源代码
void sismemberCommand(redisClient *c) {
robj *set;
if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,set,REDIS_SET)) return;
c->argv[2] = tryObjectEncoding(c->argv[2]);
if (setTypeIsMember(set,c->argv[2]))
addReply(c,shared.cone);
else
addReply(c,shared.czero);
}
int setTypeIsMember(robj *subject, robj *value) {
long long llval;
if (subject->encoding == REDIS_ENCODING_HT) {
return dictFind((dict*)subject->ptr,value) != NULL;
}
else if (subject->encoding == REDIS_ENCODING_INTSET) {
if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
return intsetFind((intset*)subject->ptr,llval);
}
} else {
redisPanic("Unknown set encoding");
}
return 0;
}
1.4 代码理解
- 先获取集合键对象,并检查对象类型。
- 调用 setTypeIsMember 判断元素是否属于集合中。
2 scardCommand
2.1 方法说明
??获取集合元素的个数。
2.2 命令实践
2.3 方法源代码
void scardCommand(redisClient *c) {
robj *o;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,REDIS_SET)) return;
addReplyLongLong(c,setTypeSize(o));
}
unsigned long setTypeSize(robj *subject) {
if (subject->encoding == REDIS_ENCODING_HT) {
return dictSize((dict*)subject->ptr);
}
else if (subject->encoding == REDIS_ENCODING_INTSET) {
return intsetLen((intset*)subject->ptr);
} else {
redisPanic("Unknown set encoding");
}
}
2.4 代码理解
- 先获取集合键对象,并检查对象类型。
- 调用 setTypeIsMember 判断元素是否属于集合中。
3 spopCommand
3.1 方法说明
??从集合中随机弹出一个元素,成功返回弹出的元素。
3.2 命令实践
3.3 方法源代码
void spopCommand(redisClient *c) {
robj *set, *ele, *aux;
int64_t llele;
int encoding;
if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
checkType(c,set,REDIS_SET)) return;
encoding = setTypeRandomElement(set,&ele,&llele);
if (encoding == REDIS_ENCODING_INTSET) {
ele = createStringObjectFromLongLong(llele);
set->ptr = intsetRemove(set->ptr,llele,NULL);
} else {
incrRefCount(ele);
setTypeRemove(set,ele);
}
notifyKeyspaceEvent(REDIS_NOTIFY_SET,"spop",c->argv[1],c->db->id);
aux = createStringObject("SREM",4);
rewriteClientCommandVector(c,3,aux,c->argv[1],ele);
decrRefCount(ele);
decrRefCount(aux);
addReplyBulk(c,ele);
if (setTypeSize(set) == 0) {
dbDelete(c->db,c->argv[1]);
notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",c->argv[1],c->db->id);
}
signalModifiedKey(c->db,c->argv[1]);
server.dirty++;
}
int setTypeRandomElement(robj *setobj, robj **objele, int64_t *llele) {
if (setobj->encoding == REDIS_ENCODING_HT) {
dictEntry *de = dictGetRandomKey(setobj->ptr);
*objele = dictGetKey(de);
} else if (setobj->encoding == REDIS_ENCODING_INTSET) {
*llele = intsetRandom(setobj->ptr);
} else {
redisPanic("Unknown set encoding");
}
return setobj->encoding;
}
3.4 代码理解
- 获取集合键对象,并判断类型。
- 调用 setTypeRandomElement 方法 随机获取集合中的一个元素。
- 根据数据结构调用相应的方法,删除这个元素。
- 触发 spop 类型触发事件。
- 如果集合中没有元素的话,则需要将集合删除,并触发del 类型触发事件。
- 标记键被修改。
4 总结
- spop 是从集合中随机弹出一个元素。
|