mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
BRPOPLPUSH.
This commit is contained in:
parent
8a979f0390
commit
b2a7fd0cf7
@ -89,6 +89,7 @@ struct redisCommand readonlyCommandTable[] = {
|
||||
{"rpop",rpopCommand,2,0,NULL,1,1,1},
|
||||
{"lpop",lpopCommand,2,0,NULL,1,1,1},
|
||||
{"brpop",brpopCommand,-3,0,NULL,1,1,1},
|
||||
{"brpoplpush",brpoplpushCommand,4,REDIS_CMD_DENYOOM,NULL,1,2,1},
|
||||
{"blpop",blpopCommand,-3,0,NULL,1,1,1},
|
||||
{"llen",llenCommand,2,0,NULL,1,1,1},
|
||||
{"lindex",lindexCommand,3,0,NULL,1,1,1},
|
||||
|
@ -321,6 +321,7 @@ typedef struct redisClient {
|
||||
int blocking_keys_num; /* Number of blocking keys */
|
||||
time_t blockingto; /* Blocking operation timeout. If UNIX current time
|
||||
* is >= blockingto then the operation timed out. */
|
||||
robj *blocking_target;
|
||||
list *io_keys; /* Keys this client is waiting to be loaded from the
|
||||
* swap file in order to continue. */
|
||||
list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */
|
||||
@ -961,6 +962,7 @@ void execCommand(redisClient *c);
|
||||
void discardCommand(redisClient *c);
|
||||
void blpopCommand(redisClient *c);
|
||||
void brpopCommand(redisClient *c);
|
||||
void brpoplpushCommand(redisClient *c);
|
||||
void appendCommand(redisClient *c);
|
||||
void substrCommand(redisClient *c);
|
||||
void strlenCommand(redisClient *c);
|
||||
|
37
src/t_list.c
37
src/t_list.c
@ -777,9 +777,28 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
|
||||
redisAssert(ln != NULL);
|
||||
receiver = ln->value;
|
||||
|
||||
if (receiver->blocking_target == NULL) {
|
||||
addReplyMultiBulkLen(receiver,2);
|
||||
addReplyBulk(receiver,key);
|
||||
addReplyBulk(receiver,ele);
|
||||
}
|
||||
else {
|
||||
receiver->argc++;
|
||||
|
||||
robj *dobj = lookupKeyWrite(receiver->db,receiver->blocking_target);
|
||||
if (dobj && checkType(receiver,dobj,REDIS_LIST)) return 0;
|
||||
|
||||
addReplyBulk(receiver,ele);
|
||||
|
||||
/* Create the list if the key does not exist */
|
||||
if (!dobj) {
|
||||
dobj = createZiplistObject();
|
||||
dbAdd(receiver->db,receiver->blocking_target,dobj);
|
||||
}
|
||||
|
||||
listTypePush(dobj,ele,REDIS_HEAD);
|
||||
}
|
||||
|
||||
unblockClientWaitingData(receiver);
|
||||
return 1;
|
||||
}
|
||||
@ -814,6 +833,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
|
||||
robj *argv[2], **orig_argv;
|
||||
int orig_argc;
|
||||
|
||||
if (c->blocking_target == NULL) {
|
||||
/* We need to alter the command arguments before to call
|
||||
* popGenericCommand() as the command takes a single key. */
|
||||
orig_argv = c->argv;
|
||||
@ -829,11 +849,20 @@ void blockingPopGenericCommand(redisClient *c, int where) {
|
||||
* because it is... */
|
||||
addReplyMultiBulkLen(c,2);
|
||||
addReplyBulk(c,argv[1]);
|
||||
|
||||
popGenericCommand(c,where);
|
||||
|
||||
/* Fix the client structure with the original stuff */
|
||||
c->argv = orig_argv;
|
||||
c->argc = orig_argc;
|
||||
}
|
||||
else {
|
||||
c->argv[2] = c->blocking_target;
|
||||
c->blocking_target = NULL;
|
||||
|
||||
rpoplpushCommand(c);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -860,3 +889,11 @@ void blpopCommand(redisClient *c) {
|
||||
void brpopCommand(redisClient *c) {
|
||||
blockingPopGenericCommand(c,REDIS_TAIL);
|
||||
}
|
||||
|
||||
void brpoplpushCommand(redisClient *c) {
|
||||
c->blocking_target = c->argv[2];
|
||||
c->argv[2] = c->argv[3];
|
||||
c->argc--;
|
||||
|
||||
blockingPopGenericCommand(c,REDIS_TAIL);
|
||||
}
|
||||
|
@ -127,6 +127,55 @@ start_server {
|
||||
assert_equal 0 [r llen blist1]
|
||||
assert_equal 1 [r llen blist2]
|
||||
}
|
||||
|
||||
test "BRPOPLPUSH - $type" {
|
||||
r del target
|
||||
|
||||
set rd [redis_deferring_client]
|
||||
create_$type blist "a b $large c d"
|
||||
|
||||
$rd brpoplpush blist target 1
|
||||
assert_equal d [$rd read]
|
||||
|
||||
assert_equal d [r rpop target]
|
||||
assert_equal "a b $large c" [r lrange blist 0 -1]
|
||||
}
|
||||
}
|
||||
|
||||
test "BRPOPLPUSH with zero timeout should block indefinitely" {
|
||||
set rd [redis_deferring_client]
|
||||
r del blist target
|
||||
$rd brpoplpush blist target 0
|
||||
after 1000
|
||||
r rpush blist foo
|
||||
assert_equal foo [$rd read]
|
||||
assert_equal {foo} [r lrange target 0 -1]
|
||||
}
|
||||
|
||||
test "BRPOPLPUSH with wrong source type" {
|
||||
set rd [redis_deferring_client]
|
||||
r del blist target
|
||||
r set blist nolist
|
||||
$rd brpoplpush blist target 1
|
||||
assert_error "ERR*wrong kind*" {$rd read}
|
||||
}
|
||||
|
||||
test "BRPOPLPUSH with wrong destination type" {
|
||||
set rd [redis_deferring_client]
|
||||
r del blist target
|
||||
r set target nolist
|
||||
r lpush blist foo
|
||||
$rd brpoplpush blist target 1
|
||||
assert_error "ERR*wrong kind*" {$rd read}
|
||||
|
||||
set rd [redis_deferring_client]
|
||||
r del blist target
|
||||
r set target nolist
|
||||
$rd brpoplpush blist target 0
|
||||
after 1000
|
||||
r rpush blist foo
|
||||
assert_error "ERR*wrong kind*" {$rd read}
|
||||
assert_equal {foo} [r lrange blist 0 -1]
|
||||
}
|
||||
|
||||
foreach {pop} {BLPOP BRPOP} {
|
||||
|
Loading…
Reference in New Issue
Block a user