Handle BRPOPLPUSH inside a transaction.

This commit is contained in:
Damian Janowski & Michel Martens 2010-11-09 10:31:02 -03:00 committed by Michel Martens
parent ba3b474111
commit 7c25a43adc
2 changed files with 51 additions and 26 deletions

View File

@ -790,16 +790,20 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
receiver = ln->value; receiver = ln->value;
if (receiver->bstate.target == NULL) { if (receiver->bstate.target == NULL) {
/* BRPOP/BLPOP return a multi-bulk with the name
* of the popped list */
addReplyMultiBulkLen(receiver,2); addReplyMultiBulkLen(receiver,2);
addReplyBulk(receiver,key); addReplyBulk(receiver,key);
addReplyBulk(receiver,ele); addReplyBulk(receiver,ele);
} }
else { else {
/* BRPOPLPUSH */
robj *dobj = lookupKeyWrite(receiver->db,receiver->bstate.target); robj *dobj = lookupKeyWrite(receiver->db,receiver->bstate.target);
if (dobj && checkType(receiver,dobj,REDIS_LIST)) return 0; if (dobj && checkType(receiver,dobj,REDIS_LIST)) return 0;
addReplyBulk(receiver,ele); addReplyBulk(receiver,ele);
if (!handleClientsWaitingListPush(receiver, receiver->bstate.target, ele)) {
/* Create the list if the key does not exist */ /* Create the list if the key does not exist */
if (!dobj) { if (!dobj) {
dobj = createZiplistObject(); dobj = createZiplistObject();
@ -808,6 +812,7 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
listTypePush(dobj, ele, REDIS_HEAD); listTypePush(dobj, ele, REDIS_HEAD);
} }
}
unblockClientWaitingData(receiver); unblockClientWaitingData(receiver);
return 1; return 1;
@ -911,20 +916,27 @@ void brpoplpushCommand(redisClient *c) {
robj *key = lookupKeyWrite(c->db, c->argv[1]); robj *key = lookupKeyWrite(c->db, c->argv[1]);
if (key == NULL) { if (key == NULL) {
// block
if (c->flags & REDIS_MULTI) { if (c->flags & REDIS_MULTI) {
/* Blocking against an empty list in a multi state
* returns immediately. */
addReply(c, shared.nullmultibulk); addReply(c, shared.nullmultibulk);
} else { } else {
if (timeout > 0) timeout += time(NULL); if (timeout > 0) timeout += time(NULL);
/* The list is empty and the client blocks. */
blockForKeys(c, c->argv + 1, 1, timeout, c->argv[2]); blockForKeys(c, c->argv + 1, 1, timeout, c->argv[2]);
} }
} else if (key->type != REDIS_LIST) { } else {
if (key->type != REDIS_LIST) {
addReply(c, shared.wrongtypeerr); addReply(c, shared.wrongtypeerr);
} else { } else {
// The list exists and has elements.
/* The list exists and has elements, so
* the regular rpoplpushCommand is executed. */
redisAssert(listTypeLength(key) > 0); redisAssert(listTypeLength(key) > 0);
rpoplpushCommand(c); rpoplpushCommand(c);
} }
} }
}

View File

@ -152,6 +152,19 @@ start_server {
assert_equal {foo} [r lrange target 0 -1] assert_equal {foo} [r lrange target 0 -1]
} }
test "BRPOPLPUSH with a client BLPOPing the target list" {
set rd [redis_deferring_client]
set rd2 [redis_deferring_client]
r del blist target
$rd2 blpop target 0
$rd brpoplpush blist target 0
after 1000
r rpush blist foo
assert_equal foo [$rd read]
assert_equal {target foo} [$rd2 read]
assert_equal 0 [r exists target]
}
test "BRPOPLPUSH with wrong source type" { test "BRPOPLPUSH with wrong source type" {
set rd [redis_deferring_client] set rd [redis_deferring_client]
r del blist target r del blist target
@ -178,7 +191,7 @@ start_server {
assert_equal {foo} [r lrange blist 0 -1] assert_equal {foo} [r lrange blist 0 -1]
} }
test {BRPOPLPUSH inside a transaction} { test "BRPOPLPUSH inside a transaction" {
r del xlist target r del xlist target
r lpush xlist foo r lpush xlist foo
r lpush xlist bar r lpush xlist bar