| 779 | } |
| 780 | |
| 781 | void lmoveGenericCommand(client *c, int wherefrom, int whereto) { |
| 782 | robj *sobj, *value; |
| 783 | if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.null[c->resp])) |
| 784 | == NULL || checkType(c,sobj,OBJ_LIST)) return; |
| 785 | |
| 786 | if (listTypeLength(sobj) == 0) { |
| 787 | /* This may only happen after loading very old RDB files. Recent |
| 788 | * versions of Redis delete keys of empty lists. */ |
| 789 | addReplyNull(c); |
| 790 | } else { |
| 791 | robj *dobj = lookupKeyWrite(c->db,c->argv[2]); |
| 792 | robj *touchedkey = c->argv[1]; |
| 793 | |
| 794 | if (checkType(c,dobj,OBJ_LIST)) return; |
| 795 | value = listTypePop(sobj,wherefrom); |
| 796 | serverAssert(value); /* assertion for valgrind (avoid NPD) */ |
| 797 | lmoveHandlePush(c,c->argv[2],dobj,value,whereto); |
| 798 | |
| 799 | /* listTypePop returns an object with its refcount incremented */ |
| 800 | decrRefCount(value); |
| 801 | |
| 802 | /* Delete the source list when it is empty */ |
| 803 | notifyKeyspaceEvent(NOTIFY_LIST, |
| 804 | wherefrom == LIST_HEAD ? "lpop" : "rpop", |
| 805 | touchedkey, |
| 806 | c->db->id); |
| 807 | if (listTypeLength(sobj) == 0) { |
| 808 | dbDelete(c->db,touchedkey); |
| 809 | notifyKeyspaceEvent(NOTIFY_GENERIC,"del", |
| 810 | touchedkey,c->db->id); |
| 811 | } |
| 812 | signalModifiedKey(c,c->db,touchedkey); |
| 813 | g_pserver->dirty++; |
| 814 | if (c->cmd->proc == blmoveCommand) { |
| 815 | rewriteClientCommandVector(c,5,shared.lmove, |
| 816 | c->argv[1],c->argv[2],c->argv[3],c->argv[4]); |
| 817 | } else if (c->cmd->proc == brpoplpushCommand) { |
| 818 | rewriteClientCommandVector(c,3,shared.rpoplpush, |
| 819 | c->argv[1],c->argv[2]); |
| 820 | } |
| 821 | } |
| 822 | } |
| 823 | |
| 824 | /* LMOVE <source> <destination> (LEFT|RIGHT) (LEFT|RIGHT) */ |
| 825 | void lmoveCommand(client *c) { |
no test coverage detected