void lremCommand(redisClient *c) { robj *subject, *obj; obj = c->argv[3] = tryObjectEncoding(c->argv[3]); long toremove; long removed = 0; listTypeEntry entry; int slotnum = keyHashSlot(c->argv[1]->ptr, sdslen(c->argv[1]->ptr)); if ((getLongFromObjectOrReply(c, c->argv[2], &toremove, NULL) != REDIS_OK)) return; subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero,slotnum); if (subject == NULL || checkType(c,subject,REDIS_LIST)) return; /* Make sure obj is raw when we're dealing with a ziplist */ if (subject->encoding == REDIS_ENCODING_ZIPLIST) obj = getDecodedObject(obj); listTypeIterator *li; if (toremove < 0) { toremove = -toremove; li = listTypeInitIterator(subject,-1,REDIS_HEAD); } else { li = listTypeInitIterator(subject,0,REDIS_TAIL); } while (listTypeNext(li,&entry)) { if (listTypeEqual(&entry,obj)) { listTypeDelete(&entry); server.dirty++; removed++; if (toremove && removed == toremove) break; } } listTypeReleaseIterator(li); /* Clean up raw encoded object */ if (subject->encoding == REDIS_ENCODING_ZIPLIST) decrRefCount(obj); if (listTypeLength(subject) == 0) dbDelete(c->db,c->argv[1],slotnum); addReplyLongLong(c,removed); if (removed) signalModifiedKey(c->db,c->argv[1],slotnum); }
void lremCommand(client *c) { robj *subject, *obj; obj = c->argv[3]; long toremove; long removed = 0; if ((getLongFromObjectOrReply(c, c->argv[2], &toremove, NULL) != C_OK)) return; subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero); if (subject == NULL || checkType(c,subject,OBJ_LIST)) return; listTypeIterator *li; if (toremove < 0) { toremove = -toremove; li = listTypeInitIterator(subject,-1,LIST_HEAD); } else { li = listTypeInitIterator(subject,0,LIST_TAIL); } listTypeEntry entry; while (listTypeNext(li,&entry)) { if (listTypeEqual(&entry,obj)) { listTypeDelete(li, &entry); server.dirty++; removed++; if (toremove && removed == toremove) break; } } listTypeReleaseIterator(li); if (removed) { signalModifiedKey(c->db,c->argv[1]); notifyKeyspaceEvent(NOTIFY_GENERIC,"lrem",c->argv[1],c->db->id); } if (listTypeLength(subject) == 0) { dbDelete(c->db,c->argv[1]); notifyKeyspaceEvent(NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } addReplyLongLong(c,removed); }
void lremCommand(redisClient *c) { robj *subject, *obj = c->argv[3]; int toremove = atoi(c->argv[2]->ptr); int removed = 0; listTypeEntry entry; subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero); if (subject == NULL || checkType(c,subject,REDIS_LIST)) return; /* Make sure obj is raw when we're dealing with a ziplist */ if (subject->encoding == REDIS_ENCODING_ZIPLIST) obj = getDecodedObject(obj); listTypeIterator *li; if (toremove < 0) { toremove = -toremove; li = listTypeInitIterator(subject,-1,REDIS_HEAD); } else { li = listTypeInitIterator(subject,0,REDIS_TAIL); } while (listTypeNext(li,&entry)) { if (listTypeEqual(&entry,obj)) { listTypeDelete(&entry); server.dirty++; removed++; if (toremove && removed == toremove) break; } } listTypeReleaseIterator(li); /* Clean up raw encoded object */ if (subject->encoding == REDIS_ENCODING_ZIPLIST) decrRefCount(obj); if (listTypeLength(subject) == 0) dbDelete(c->db,c->argv[1]); addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",removed)); if (removed) touchWatchedKey(c->db,c->argv[1]); }
// LREM key count value // LREM命令 void lremCommand(client *c) { robj *subject, *obj; obj = c->argv[3]; long toremove; long removed = 0; //将字符串类型的count参数转换为long类型的整数,保存在toremove中 if ((getLongFromObjectOrReply(c, c->argv[2], &toremove, NULL) != C_OK)) return; //以写操作读取出key对象的value值 subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero); //如果key不存在或value对象不是列表类型则直接返回 if (subject == NULL || checkType(c,subject,OBJ_LIST)) return; listTypeIterator *li; if (toremove < 0) { //如果toremove小于零,则从尾部向头部删除 toremove = -toremove; //创建迭代器,指向尾部元素 li = listTypeInitIterator(subject,-1,LIST_HEAD); } else { //如果toremove大于等于零,则从头部向尾部删除,创建迭代器 li = listTypeInitIterator(subject,0,LIST_TAIL); } listTypeEntry entry; //遍历列表,保存迭代器当前指向的entry while (listTypeNext(li,&entry)) { //如果当前entry的值是obj if (listTypeEqual(&entry,obj)) { //删除当前的entry listTypeDelete(li, &entry); //更新脏键 server.dirty++; //更新计数器 removed++; //如果删除了count个,则跳出循环 if (toremove && removed == toremove) break; } } //释放迭代器 listTypeReleaseIterator(li); //如果删除成功 if (removed) { //当数据库的键被改动,则会调用该函数发送信号 signalModifiedKey(c->db,c->argv[1]); //发送"lrem"时间通知 notifyKeyspaceEvent(NOTIFY_GENERIC,"lrem",c->argv[1],c->db->id); } //如果将列表中的元素全部删除完了 if (listTypeLength(subject) == 0) { //从数据库中删除键key dbDelete(c->db,c->argv[1]); //发送"del"时间通知 notifyKeyspaceEvent(NOTIFY_GENERIC,"del",c->argv[1],c->db->id); } //发送删除元素的个数给client addReplyLongLong(c,removed); }