From d33278d1601bda80987a6f4ad4b2319fb2f7e972 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 12 Apr 2010 12:29:37 +0200 Subject: [PATCH] implemented HMSET --- redis-cli.c | 1 + redis.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ redis.tcl | 2 +- test-redis.tcl | 37 +++++++++++++++++++++++----- 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/redis-cli.c b/redis-cli.c index 5760da15a..febc7cec0 100644 --- a/redis-cli.c +++ b/redis-cli.c @@ -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 667ad4e76..6b23c7bc3 100644 --- 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]); diff --git a/redis.tcl b/redis.tcl index a1f3f566a..233e2c9fe 100644 --- 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) {} } diff --git a/test-redis.tcl b/test-redis.tcl index f7fe39b04..c986baff7 100644 --- a/test-redis.tcl +++ b/test-redis.tcl @@ -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]