]> git.saurik.com Git - redis.git/commitdiff
implemented HMSET
authorPieter Noordhuis <pcnoordhuis@gmail.com>
Mon, 12 Apr 2010 10:29:37 +0000 (12:29 +0200)
committerPieter Noordhuis <pcnoordhuis@gmail.com>
Mon, 12 Apr 2010 10:29:37 +0000 (12:29 +0200)
redis-cli.c
redis.c
redis.tcl
test-redis.tcl

index 5760da15a803b548ab25621cace86861daa7500f..febc7cec08317cfbc51d48178a92c3f6c5d84b34 100644 (file)
@@ -150,6 +150,7 @@ static struct redisCommand cmdTable[] = {
     {"exec",1,REDIS_CMD_INLINE},
     {"discard",1,REDIS_CMD_INLINE},
     {"hset",4,REDIS_CMD_MULTIBULK},
+    {"hmset",-4,REDIS_CMD_MULTIBULK},
     {"hincrby",4,REDIS_CMD_INLINE},
     {"hget",3,REDIS_CMD_BULK},
     {"hdel",3,REDIS_CMD_BULK},
diff --git a/redis.c b/redis.c
index 667ad4e760704feb0f5b17ae529628b9910aa739..6b23c7bc3b17a80ca305d1c79e1538ee7f9eb5c7 100644 (file)
--- a/redis.c
+++ b/redis.c
@@ -704,6 +704,7 @@ static void substrCommand(redisClient *c);
 static void zrankCommand(redisClient *c);
 static void zrevrankCommand(redisClient *c);
 static void hsetCommand(redisClient *c);
+static void hmsetCommand(redisClient *c);
 static void hgetCommand(redisClient *c);
 static void hdelCommand(redisClient *c);
 static void hlenCommand(redisClient *c);
@@ -780,6 +781,7 @@ static struct redisCommand cmdTable[] = {
     {"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
     {"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
     {"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
+    {"hmset",hmsetCommand,-4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
     {"hincrby",hincrbyCommand,4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
     {"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
     {"hdel",hdelCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
@@ -6004,6 +6006,70 @@ static void hsetCommand(redisClient *c) {
     addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",update == 0));
 }
 
+static void hmsetCommand(redisClient *c) {
+    int i;
+    robj *o, *key, *val;
+
+    if ((c->argc % 2) == 1) {
+        addReplySds(c,sdsnew("-ERR wrong number of arguments for HMSET\r\n"));
+        return;
+    }
+
+    if ((o = lookupKeyWrite(c->db,c->argv[1])) == NULL) {
+        o = createHashObject();
+        dictAdd(c->db->dict,c->argv[1],o);
+        incrRefCount(c->argv[1]);
+    } else {
+        if (o->type != REDIS_HASH) {
+            addReply(c,shared.wrongtypeerr);
+            return;
+        }
+    }
+
+    /* We want to convert the zipmap into an hash table right now if the
+     * entry to be added is too big. */
+    if (o->encoding == REDIS_ENCODING_ZIPMAP) {
+        for (i = 2; i < c->argc; i+=2) {
+            if ((c->argv[i]->encoding == REDIS_ENCODING_RAW &&
+                  sdslen(c->argv[i]->ptr) > server.hash_max_zipmap_value) ||
+                (c->argv[i+1]->encoding == REDIS_ENCODING_RAW &&
+                  sdslen(c->argv[i+1]->ptr) > server.hash_max_zipmap_value)) {
+                convertToRealHash(o);
+                break;
+            }
+        }
+    }
+
+    if (o->encoding == REDIS_ENCODING_ZIPMAP) {
+        unsigned char *zm = o->ptr;
+
+        for (i = 2; i < c->argc; i+=2) {
+            key = getDecodedObject(c->argv[i]);
+            val = getDecodedObject(c->argv[i+1]);
+            zm = zipmapSet(zm,key->ptr,sdslen(key->ptr),
+                              val->ptr,sdslen(val->ptr),NULL);
+            decrRefCount(key);
+            decrRefCount(val);
+            o->ptr = zm;
+        }
+
+        /* And here there is the second check for hash conversion. */
+        if (zipmapLen(zm) > server.hash_max_zipmap_entries)
+            convertToRealHash(o);
+    } else {
+        for (i = 2; i < c->argc; i+=2) {
+            key = tryObjectEncoding(c->argv[i]);
+            val = tryObjectEncoding(c->argv[i+1]);
+            if (dictReplace(o->ptr,key,val)) {
+                incrRefCount(key);
+            }
+            incrRefCount(val);
+        }
+    }
+
+    addReply(c, shared.ok);
+}
+
 static void hincrbyCommand(redisClient *c) {
     long long value = 0, incr = 0;
     robj *o = lookupKeyWrite(c->db,c->argv[1]);
index a1f3f566a199a28241dc71f79c21471f53c6d431..233e2c9fe1d17c5e0d98bbdd75c2f86b47193da2 100644 (file)
--- a/redis.tcl
+++ b/redis.tcl
@@ -46,7 +46,7 @@ foreach redis_bulk_cmd {
 
 # Flag commands requiring last argument as a bulk write operation
 foreach redis_multibulk_cmd {
-    mset msetnx hset
+    mset msetnx hset hmset
 } {
     set ::redis::multibulkarg($redis_multibulk_cmd) {}
 }
index f7fe39b0487c2b7eaea6366c01aab766bb2c4d4e..c986baff7bd27ee2785a2a22ed562242c0780ae0 100644 (file)
@@ -1614,6 +1614,13 @@ proc main {server port} {
         set _ $err
     } {}
 
+    test {HGET against non existing key} {
+        set rv {}
+        lappend rv [$r hget smallhash __123123123__]
+        lappend rv [$r hget bighash __123123123__]
+        set _ $rv
+    } {{} {}}
+
     test {HSET in update and insert mode} {
         set rv {}
         set k [lindex [array names smallhash *] 0]
@@ -1631,12 +1638,30 @@ proc main {server port} {
         set _ $rv
     } {0 newval1 1 0 newval2 1 1 1}
 
-    test {HGET against non existing key} {
-        set rv {}
-        lappend rv [$r hget smallhash __123123123__]
-        lappend rv [$r hget bighash __123123123__]
-        set _ $rv
-    } {{} {}}
+    test {HMSET wrong number of args} {
+        catch {$r hmset smallhash key1 val1 key2} err
+        format $err
+    } {*wrong number*}
+
+    test {HMSET - small hash} {
+        set args {}
+        foreach {k v} [array get smallhash] {
+            set newval [randstring 0 8 alpha]
+            set smallhash($k) $newval
+            lappend args $k $newval
+        }
+        $r hmset smallhash {*}$args
+    } {OK}
+
+    test {HMSET - big hash} {
+        set args {}
+        foreach {k v} [array get bighash] {
+            set newval [randstring 0 8 alpha]
+            set bighash($k) $newval
+            lappend args $k $newval
+        }
+        $r hmset bighash {*}$args
+    } {OK}
 
     test {HKEYS - small hash} {
         lsort [$r hkeys smallhash]