void pushGenericCommand(redisClient *c, int where) { robj *lobj = lookupKeyWrite(c->db,c->argv[1]); c->argv[2] = tryObjectEncoding(c->argv[2]); if (lobj == NULL) { if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) { addReply(c,shared.cone); return; } lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } else { if (lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) { touchWatchedKey(c->db,c->argv[1]); addReply(c,shared.cone); return; } } listTypePush(lobj,c->argv[2],where); addReplyLongLong(c,listTypeLength(lobj)); touchWatchedKey(c->db,c->argv[1]); server.dirty++; }
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) { if (!handleClientsWaitingListPush(origclient,dstkey,value)) { /* Create the list if the key does not exist */ if (!dstobj) { dstobj = createZiplistObject(); dbAdd(c->db,dstkey,dstobj); } else { signalModifiedKey(c->db,dstkey); } listTypePush(dstobj,value,REDIS_HEAD); /* Additionally propagate this PUSH operation together with * the operation performed by the command. */ { robj **argv = zmalloc(sizeof(robj*)*3); argv[0] = createStringObject("LPUSH",5); argv[1] = dstkey; argv[2] = value; incrRefCount(argv[1]); incrRefCount(argv[2]); alsoPropagate(server.lpushCommand,c->db->id,argv,3, REDIS_PROPAGATE_AOF|REDIS_PROPAGATE_REPL); } } /* Always send the pushed value to the client. */ addReplyBulk(c,value); }
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) { robj *aux; if (!handleClientsWaitingListPush(c,dstkey,value)) { /* Create the list if the key does not exist */ if (!dstobj) { dstobj = createZiplistObject(); dbAdd(c->db,dstkey,dstobj); } else { signalModifiedKey(c->db,dstkey); } listTypePush(dstobj,value,REDIS_HEAD); /* If we are pushing as a result of LPUSH against a key * watched by BLPOPLPUSH, we need to rewrite the command vector. * But if this is called directly by RPOPLPUSH (either directly * or via a BRPOPLPUSH where the popped list exists) * we should replicate the BRPOPLPUSH command itself. */ if (c != origclient) { aux = createStringObject("LPUSH",5); rewriteClientCommandVector(origclient,3,aux,dstkey,value); decrRefCount(aux); } else { /* Make sure to always use RPOPLPUSH in the replication / AOF, * even if the original command was BRPOPLPUSH. */ aux = createStringObject("RPOPLPUSH",9); rewriteClientCommandVector(origclient,3,aux,c->argv[1],c->argv[2]); decrRefCount(aux); } server.dirty++; } /* Always send the pushed value to the client. */ addReplyBulk(c,value); }
void pushGenericCommand(redisClient *c, int where) { int j, addlen = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); int may_have_waiting_clients = (lobj == NULL); if (lobj && lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (may_have_waiting_clients) { if (handleClientsWaitingListPush(c,c->argv[1],c->argv[j])) { addlen++; continue; } else { may_have_waiting_clients = 0; } } if (!lobj) { lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } listTypePush(lobj,c->argv[j],where); pushed++; } addReplyLongLong(c,addlen + (lobj ? listTypeLength(lobj) : 0)); if (pushed) signalModifiedKey(c->db,c->argv[1]); server.dirty += pushed; }
/* This is the semantic of this command: * RPOPLPUSH srclist dstlist: * IF LLEN(srclist) > 0 * element = RPOP srclist * LPUSH dstlist element * RETURN element * ELSE * RETURN nil * END * END * * The idea is to be able to get an element from a list in a reliable way * since the element is not just returned but pushed against another list * as well. This command was originally proposed by Ezra Zygmuntowicz. */ void rpoplpushcommand(redisClient *c) { robj *sobj, *value; if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL || checkType(c,sobj,REDIS_LIST)) return; if (listTypeLength(sobj) == 0) { addReply(c,shared.nullbulk); } else { robj *dobj = lookupKeyWrite(c->db,c->argv[2]); if (dobj && checkType(c,dobj,REDIS_LIST)) return; value = listTypePop(sobj,REDIS_TAIL); /* Add the element to the target list (unless it's directly * passed to some BLPOP-ing client */ if (!handleClientsWaitingListPush(c,c->argv[2],value)) { /* Create the list if the key does not exist */ if (!dobj) { dobj = createZiplistObject(); dbAdd(c->db,c->argv[2],dobj); } listTypePush(dobj,value,REDIS_HEAD); } /* Send the element to the client as reply as well */ addReplyBulk(c,value); /* listTypePop returns an object with its refcount incremented */ decrRefCount(value); /* Delete the source list when it is empty */ if (listTypeLength(sobj) == 0) dbDelete(c->db,c->argv[1]); touchWatchedKey(c->db,c->argv[1]); server.dirty++; } }
void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value) { if (!handleClientsWaitingListPush(c,dstkey,value)) { /* Create the list if the key does not exist */ if (!dstobj) { dstobj = createZiplistObject(); dbAdd(c->db,dstkey,dstobj); } else { touchWatchedKey(c->db,dstkey); server.dirty++; } listTypePush(dstobj,value,REDIS_HEAD); } /* Always send the pushed value to the client. */ addReplyBulk(c,value); }
void pushGenericCommand(redisClient *c, int where) { int j, waiting = 0, pushed = 0; robj *lobj = lookupKeyWrite(c->db,c->argv[1]); int may_have_waiting_clients = (lobj == NULL); if (lobj && lobj->type != REDIS_LIST) { addReply(c,shared.wrongtypeerr); return; } for (j = 2; j < c->argc; j++) { c->argv[j] = tryObjectEncoding(c->argv[j]); if (may_have_waiting_clients) { if (handleClientsWaitingListPush(c,c->argv[1],c->argv[j])) { waiting++; continue; } else { may_have_waiting_clients = 0; } } if (!lobj) { lobj = createZiplistObject(); dbAdd(c->db,c->argv[1],lobj); } listTypePush(lobj,c->argv[j],where); pushed++; } addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0)); if (pushed) signalModifiedKey(c->db,c->argv[1]); server.dirty += pushed; /* Alter the replication of the command accordingly to the number of * list elements delivered to clients waiting into a blocking operation. * We do that only if there were waiting clients, and only if still some * element was pushed into the list (othewise dirty is 0 and nothign will * be propagated). */ if (waiting && pushed) { /* CMD KEY a b C D E */ for (j = 0; j < waiting; j++) decrRefCount(c->argv[j+2]); memmove(c->argv+2,c->argv+2+waiting,sizeof(robj*)*pushed); c->argc -= waiting; } }