From 12f9d551b60e5471baa70b6aa2237bf25d25f70a Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 11 Nov 2009 18:38:37 +0100 Subject: [PATCH] LPUSHPOP first implementation --- TODO | 2 +- redis-cli.c | 1 + redis.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-- test-redis.tcl | 16 ++++++++---- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index b63a4a43..b5d1d83c 100644 --- a/TODO +++ b/TODO @@ -3,13 +3,13 @@ VERSION 1.1 TODO * For now only the last argument gets integer encoded, so make sure that: 1) every multi bulk commands implemented will have the last arg that is indeed a value, and not used otherwise. 2) to explicitly call the function to encode the object in MSET and other commands where there are multiple "values". * Man pages for MSET MSETNX and SRANDMEMBER, Z-commands, ... * ZSETs missing stuff: ZINCRBY -* Add all the missing symbols for the static functions into the table. Crete a Tcl script to check this. This backtrace on segfault is indeed *very* useful. * Use strcoll() to compare objects in sorted sets, like it already happens for SORT. * LMOVE, as discussed in the Redis group. * EXPIRE, EXPIREAT, ZSCORE tests. * Write docs for the "STORE" operaiton of SORT, and GET "#" option. * Append only mode: testing and a command to rebuild the log from scratch. * Profiling and optimizations. For instance the commands lookup is probably starting to eat too CPU being a simple list. To implement binary search or an hash table lookup can be a win probably. +* Redis-cli should be able to select a different DB than 0 using some switch. VERSION 1.2 TODO diff --git a/redis-cli.c b/redis-cli.c index 2ec17541..c2d43a59 100644 --- a/redis-cli.c +++ b/redis-cli.c @@ -76,6 +76,7 @@ static struct redisCommand cmdTable[] = { {"lrange",4,REDIS_CMD_INLINE}, {"ltrim",4,REDIS_CMD_INLINE}, {"lrem",4,REDIS_CMD_BULK}, + {"lpoppush",3,REDIS_CMD_BULK}, {"sadd",3,REDIS_CMD_BULK}, {"srem",3,REDIS_CMD_BULK}, {"smove",4,REDIS_CMD_BULK}, diff --git a/redis.c b/redis.c index 12bd8567..e6da5f85 100644 --- a/redis.c +++ b/redis.c @@ -446,6 +446,7 @@ static void flushdbCommand(redisClient *c); static void flushallCommand(redisClient *c); static void sortCommand(redisClient *c); static void lremCommand(redisClient *c); +static void lpoppushCommand(redisClient *c); static void infoCommand(redisClient *c); static void mgetCommand(redisClient *c); static void monitorCommand(redisClient *c); @@ -489,6 +490,7 @@ static struct redisCommand cmdTable[] = { {"lrange",lrangeCommand,4,REDIS_CMD_INLINE}, {"ltrim",ltrimCommand,4,REDIS_CMD_INLINE}, {"lrem",lremCommand,4,REDIS_CMD_BULK}, + {"lpoppush",lpoppushCommand,3,REDIS_CMD_BULK}, {"sadd",saddCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM}, {"srem",sremCommand,3,REDIS_CMD_BULK}, {"smove",smoveCommand,4,REDIS_CMD_BULK}, @@ -1403,10 +1405,10 @@ static void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) c->sentlen = 0; } /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT - * bytes, in a single threaded server it's a good idea to server + * bytes, in a single threaded server it's a good idea to serve * other clients as well, even if a very large request comes from * super fast link that is always able to accept data (in real world - * terms think to 'KEYS *' against the loopback interfae) */ + * scenario think about 'KEYS *' against the loopback interfae) */ if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break; } if (nwritten == -1) { @@ -3468,6 +3470,70 @@ static void lremCommand(redisClient *c) { } } +/* This is the semantic of this command: + * LPOPPUSH 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. + */ +static void lpoppushCommand(redisClient *c) { + robj *sobj; + + sobj = lookupKeyWrite(c->db,c->argv[1]); + if (sobj == NULL) { + addReply(c,shared.nullbulk); + } else { + if (sobj->type != REDIS_LIST) { + addReply(c,shared.wrongtypeerr); + } else { + list *srclist = sobj->ptr; + listNode *ln = listLast(srclist); + + if (ln == NULL) { + addReply(c,shared.nullbulk); + } else { + robj *dobj = lookupKeyWrite(c->db,c->argv[2]); + robj *ele = listNodeValue(ln); + list *dstlist; + + if (dobj == NULL) { + + /* Create the list if the key does not exist */ + dobj = createListObject(); + dictAdd(c->db->dict,c->argv[2],dobj); + incrRefCount(c->argv[2]); + } else if (dobj->type != REDIS_LIST) { + addReply(c,shared.wrongtypeerr); + return; + } + /* Add the element to the target list */ + dstlist = dobj->ptr; + listAddNodeHead(dstlist,ele); + incrRefCount(ele); + + /* Send the element to the client as reply as well */ + addReplyBulkLen(c,ele); + addReply(c,ele); + addReply(c,shared.crlf); + + /* Finally remove the element from the source list */ + listDelNode(srclist,ln); + server.dirty++; + } + } + } +} + + /* ==================================== Sets ================================ */ static void saddCommand(redisClient *c) { diff --git a/test-redis.tcl b/test-redis.tcl index 468c25c5..eb061029 100644 --- a/test-redis.tcl +++ b/test-redis.tcl @@ -916,7 +916,7 @@ proc stress {} { set randval [expr int(rand()*10000)] set randidx0 [expr int(rand()*10)] set randidx1 [expr int(rand()*10)] - set cmd [expr int(rand()*10)] + set cmd [expr int(rand()*20)] catch { if {$cmd == 0} {$r set $randkey $randval} if {$cmd == 1} {$r get $randkey} @@ -924,10 +924,16 @@ proc stress {} { if {$cmd == 3} {$r lpush $randkey $randval} if {$cmd == 4} {$r rpop $randkey} if {$cmd == 5} {$r del $randkey} - if {$cmd == 6} {$r lrange $randkey $randidx0 $randidx1} - if {$cmd == 7} {$r ltrim $randkey $randidx0 $randidx1} - if {$cmd == 8} {$r lindex $randkey $randidx0} - if {$cmd == 9} {$r lset $randkey $randidx0 $randval} + if {$cmd == 6} {$r llen $randkey} + if {$cmd == 7} {$r lrange $randkey $randidx0 $randidx1} + if {$cmd == 8} {$r ltrim $randkey $randidx0 $randidx1} + if {$cmd == 9} {$r lindex $randkey $randidx0} + if {$cmd == 10} {$r lset $randkey $randidx0 $randval} + if {$cmd == 11} {$r sadd $randkey $randval} + if {$cmd == 12} {$r srem $randkey $randval} + if {$cmd == 13} {$r smove $randkey $randval} + if {$cmd == 14} {$r scard $randkey} + if {$cmd == 15} {$r expire $randkey [expr $randval%60]} } flush stdout }