diff --git a/src/redis.c b/src/redis.c index 5223bae5..94bd1688 100644 --- a/src/redis.c +++ b/src/redis.c @@ -85,8 +85,8 @@ struct redisCommand readonlyCommandTable[] = { {"incr",incrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"decr",decrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"mget",mgetCommand,-2,0,NULL,1,-1,1}, - {"rpush",rpushCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1}, - {"lpush",lpushCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1}, + {"rpush",rpushCommand,-3,REDIS_CMD_DENYOOM,NULL,1,1,1}, + {"lpush",lpushCommand,-3,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"rpushx",rpushxCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"lpushx",lpushxCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"linsert",linsertCommand,5,REDIS_CMD_DENYOOM,NULL,1,1,1}, diff --git a/src/t_list.c b/src/t_list.c index 47c927db..3c750912 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -259,30 +259,35 @@ void listTypeConvert(robj *subject, int enc) { *----------------------------------------------------------------------------*/ void pushGenericCommand(redisClient *c, int where) { + int j, addlen = 0, pushed = 0; 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; - } + int may_have_waiting_clients = (lobj == NULL); + + if (lobj && lobj->type != REDIS_LIST) { + addReply(c,shared.wrongtypeerr); + return; } - listTypePush(lobj,c->argv[2],where); - addReplyLongLong(c,listTypeLength(lobj)); - touchWatchedKey(c->db,c->argv[1]); - server.dirty++; + + 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) touchWatchedKey(c->db,c->argv[1]); + server.dirty += pushed; } void lpushCommand(redisClient *c) { diff --git a/src/version.h b/src/version.h index 6ae276d8..db97d903 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define REDIS_VERSION "2.2.4" +#define REDIS_VERSION "2.3.1" diff --git a/tests/unit/type/list.tcl b/tests/unit/type/list.tcl index 6b128b72..b6055b26 100644 --- a/tests/unit/type/list.tcl +++ b/tests/unit/type/list.tcl @@ -55,6 +55,13 @@ start_server { assert_equal $largevalue(linkedlist) [r lindex mylist2 2] } + test {Variadic RPUSH/LPUSH} { + r del mylist + assert_equal 4 [r lpush mylist a b c d] + assert_equal 8 [r rpush mylist 0 1 2 3] + assert_equal {d c b a 0 1 2 3} [r lrange mylist 0 -1] + } + test {DEL a list - ziplist} { assert_equal 1 [r del myziplist2] assert_equal 0 [r exists myziplist2] @@ -142,6 +149,15 @@ start_server { } } + test "BLPOP with variadic LPUSH" { + set rd [redis_deferring_client] + r del blist target + $rd blpop blist 0 + assert_equal 2 [r lpush blist foo bar] + assert_equal {blist foo} [$rd read] + assert_equal bar [lindex [r lrange blist 0 -1] 0] + } + test "BRPOPLPUSH with zero timeout should block indefinitely" { set rd [redis_deferring_client] r del blist target