Added a new API to replicate an additional command after the replication of the currently executed command, in order to propagte the LPUSH originating from RPOPLPUSH and indirectly by BRPOPLPUSH.

This commit is contained in:
antirez
2012-02-28 18:03:08 +01:00
parent d8b1228bf6
commit eeb34eff52
3 changed files with 71 additions and 22 deletions

View File

@ -288,6 +288,18 @@ void pushGenericCommand(redisClient *c, int where) {
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 = 2; j < pushed+2; j++)
rewriteClientCommandArgument(c,j,c->argv[j+waiting]);
c->argc -= waiting;
}
}
void lpushCommand(redisClient *c) {
@ -655,8 +667,6 @@ void lremCommand(redisClient *c) {
*/
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) {
robj *aux;
if (!handleClientsWaitingListPush(origclient,dstkey,value)) {
/* Create the list if the key does not exist */
if (!dstobj) {
@ -666,27 +676,19 @@ void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey,
signalModifiedKey(c->db,dstkey);
}
listTypePush(dstobj,value,REDIS_HEAD);
/* If we are pushing as a result of LPUSH against a key
* watched by BRPOPLPUSH, we need to rewrite the command vector
* as an LPUSH.
*
* If this is called directly by RPOPLPUSH (either directly
* or via a BRPOPLPUSH where the popped list exists)
* we should replicate the RPOPLPUSH 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);
/* 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);
}
server.dirty++;
}
/* Always send the pushed value to the client. */
addReplyBulk(c,value);
}
@ -717,6 +719,13 @@ void rpoplpushCommand(redisClient *c) {
signalModifiedKey(c->db,touchedkey);
decrRefCount(touchedkey);
server.dirty++;
/* Replicate this as a simple RPOP since the LPUSH side is replicated
* by rpoplpushHandlePush() call if needed (it may not be needed
* if a client is blocking wait a push against the list). */
rewriteClientCommandVector(c,2,
resetRefCount(createStringObject("RPOP",4)),
c->argv[1]);
}
}