MSET and MSETNX commands implemented
authorantirez <antirez@gmail.com>
Fri, 16 Oct 2009 11:44:25 +0000 (13:44 +0200)
committerantirez <antirez@gmail.com>
Fri, 16 Oct 2009 11:44:25 +0000 (13:44 +0200)
TODO
client-libraries/tcl/redis.tcl
redis.c

diff --git a/TODO b/TODO
index 7722b34cdc1880711f585a0004b7023d5d5a1a91..531b9738c0f5bf8e93f1c6a78098d2c19c96700f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,4 +1,10 @@
- * Expiring algorithm should be adaptive, if there are a lot of keys with an expire set and many of this happen to be already expired it should be, proportionally, more aggressive.
+Pre 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".
+
+After 1.1 todo
+
+* Expiring algorithm should be adaptive, if there are a lot of keys with an expire set and many of this happen to be already expired it should be, proportionally, more aggressive.
  * Add a command to inspect the currently selected DB index
  * Consistent hashing implemented in all the client libraries having an user base
  * SORT: Don't copy the list into a vector when BY argument is constant.
index 636444de50462788255ff24933fa7f04ad2661c8..deeadf2ec308cc2cbe425c8bf2759e45c40e2201 100644 (file)
@@ -16,6 +16,7 @@ namespace eval redis {}
 set ::redis::id 0
 array set ::redis::fd {}
 array set ::redis::bulkarg {}
+array set ::redis::multibulkarg {}
 
 # Flag commands requiring last argument as a bulk write operation
 foreach redis_bulk_cmd {
@@ -23,7 +24,16 @@ foreach redis_bulk_cmd {
 } {
     set ::redis::bulkarg($redis_bulk_cmd) {}
 }
+
+# Flag commands requiring last argument as a bulk write operation
+foreach redis_multibulk_cmd {
+    mset
+} {
+    set ::redis::multibulkarg($redis_multibulk_cmd) {}
+}
+
 unset redis_bulk_cmd
+unset redis_multibulk_cmd
 
 proc redis {{server 127.0.0.1} {port 6379}} {
     set fd [socket $server $port]
@@ -36,15 +46,24 @@ proc redis {{server 127.0.0.1} {port 6379}} {
 proc ::redis::__dispatch__ {id method args} {
     set fd $::redis::fd($id)
     if {[info command ::redis::__method__$method] eq {}} {
-        set cmd "$method "
         if {[info exists ::redis::bulkarg($method)]} {
+            set cmd "$method "
             append cmd [join [lrange $args 0 end-1]]
             append cmd " [string length [lindex $args end]]\r\n"
             append cmd [lindex $args end]
+            ::redis::redis_writenl $fd $cmd
+        } elseif {[info exists ::redis::multibulkarg($method)]} {
+            set cmd "*[expr {[llength $args]}+1]\r\n"
+            append cmd "$[string length $method]\r\n$method\r\n"
+            foreach a $args {
+                append cmd "$[string length $a]\r\n$a\r\n"
+            }
+            ::redis::redis_write $fd $cmd
         } else {
+            set cmd "$method "
             append cmd [join $args]
+            ::redis::redis_writenl $fd $cmd
         }
-        ::redis::redis_writenl $fd $cmd
         ::redis::redis_read_reply $fd
     } else {
         uplevel 1 [list ::redis::__method__$method $id $fd] $args
diff --git a/redis.c b/redis.c
index f36e3b082008748fe7e0ccaa128771e24bc57a58..cf2366fa915d067a51906809f0d4fe6c7f01cf85 100644 (file)
--- a/redis.c
+++ b/redis.c
@@ -399,10 +399,13 @@ static void infoCommand(redisClient *c);
 static void mgetCommand(redisClient *c);
 static void monitorCommand(redisClient *c);
 static void expireCommand(redisClient *c);
-static void getSetCommand(redisClient *c);
+static void getsetCommand(redisClient *c);
 static void ttlCommand(redisClient *c);
 static void slaveofCommand(redisClient *c);
 static void debugCommand(redisClient *c);
+static void msetCommand(redisClient *c);
+static void msetnxCommand(redisClient *c);
+
 /*================================= Globals ================================= */
 
 /* Global vars */
@@ -441,7 +444,9 @@ static struct redisCommand cmdTable[] = {
     {"smembers",sinterCommand,2,REDIS_CMD_INLINE},
     {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
     {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM},
-    {"getset",getSetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
+    {"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
+    {"mset",msetCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
+    {"msetnx",msetnxCommand,-3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
     {"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE},
     {"select",selectCommand,2,REDIS_CMD_INLINE},
     {"move",moveCommand,3,REDIS_CMD_INLINE},
@@ -2596,7 +2601,7 @@ static void getCommand(redisClient *c) {
     }
 }
 
-static void getSetCommand(redisClient *c) {
+static void getsetCommand(redisClient *c) {
     getCommand(c);
     if (dictAdd(c->db->dict,c->argv[1],c->argv[2]) == DICT_ERR) {
         dictReplace(c->db->dict,c->argv[1],c->argv[2]);
@@ -4094,6 +4099,42 @@ static void ttlCommand(redisClient *c) {
     addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",ttl));
 }
 
+static void msetGenericCommand(redisClient *c, int nx) {
+    int j;
+
+    if ((c->argc % 2) == 0) {
+        addReplySds(c,sdsnew("-ERR wrong number of arguments\r\n"));
+        return;
+    }
+    /* Handle the NX flag. The MSETNX semantic is to return zero and don't
+     * set nothing at all if at least one already key exists. */
+    if (nx) {
+        for (j = 1; j < c->argc; j += 2) {
+            if (dictFind(c->db->dict,c->argv[j]) != NULL) {
+                addReply(c, shared.czero);
+                return;
+            }
+        }
+    }
+
+    for (j = 1; j < c->argc; j += 2) {
+        dictAdd(c->db->dict,c->argv[j],c->argv[j+1]);
+        incrRefCount(c->argv[j]);
+        incrRefCount(c->argv[j+1]);
+        removeExpire(c->db,c->argv[j]);
+    }
+    server.dirty += (c->argc-1)/2;
+    addReply(c, nx ? shared.cone : shared.ok);
+}
+
+static void msetCommand(redisClient *c) {
+    msetGenericCommand(c,0);
+}
+
+static void msetnxCommand(redisClient *c) {
+    msetGenericCommand(c,1);
+}
+
 /* =============================== Replication  ============================= */
 
 static int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
@@ -4586,7 +4627,7 @@ static struct redisFunctionSym symsTable[] = {
 {"mgetCommand", (unsigned long)mgetCommand},
 {"monitorCommand", (unsigned long)monitorCommand},
 {"expireCommand", (unsigned long)expireCommand},
-{"getSetCommand", (unsigned long)getSetCommand},
+{"getsetCommand", (unsigned long)getsetCommand},
 {"ttlCommand", (unsigned long)ttlCommand},
 {"slaveofCommand", (unsigned long)slaveofCommand},
 {"debugCommand", (unsigned long)debugCommand},
@@ -4594,6 +4635,9 @@ static struct redisFunctionSym symsTable[] = {
 {"setupSigSegvAction", (unsigned long)setupSigSegvAction},
 {"readQueryFromClient", (unsigned long)readQueryFromClient},
 {"rdbRemoveTempFile", (unsigned long)rdbRemoveTempFile},
+{"msetGenericCommand", (unsigned long)msetGenericCommand},
+{"msetCommand", (unsigned long)msetCommand},
+{"msetnxCommand", (unsigned long)msetnxCommand},
 {NULL,0}
 };