]> git.saurik.com Git - redis.git/commitdiff
LPUSHPOP first implementation
authorantirez <antirez@gmail.com>
Wed, 11 Nov 2009 17:38:37 +0000 (18:38 +0100)
committerantirez <antirez@gmail.com>
Wed, 11 Nov 2009 17:38:37 +0000 (18:38 +0100)
TODO
redis-cli.c
redis.c
test-redis.tcl

diff --git a/TODO b/TODO
index b63a4a43957ca9c564db7d85aa56fcce4b7702b2..b5d1d83c9537b56625b18fdfaaa1877827b88c8d 100644 (file)
--- 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
 
index 2ec17541a4a039eba9bc1c43ad276c1acf820e07..c2d43a5949a77b7752113ad3490332366bbbb78c 100644 (file)
@@ -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 12bd856762d9babcf8a40897dcd6297b66bdb610..e6da5f85cd8e8e518f9d5ba4889fed696bc169a4 100644 (file)
--- 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) {
index 468c25c5212a5ccc524b8ec07373242f0e854062..eb0610293bbfc30d1c1ebb81842bd6ea66ac35c6 100644 (file)
@@ -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
     }