From 92b27fe946004935f0f29277d2a762c63af55ce3 Mon Sep 17 00:00:00 2001
From: antirez <antirez@gmail.com>
Date: Mon, 15 Mar 2010 22:46:20 +0100
Subject: [PATCH] An interesting refactoring + more expressive internal API

---
 Changelog   |  3 +++
 redis-cli.c |  1 +
 redis.c     | 44 +++++++++++++++++++++++++++++++++++++++++++-
 redis.tcl   |  4 ++--
 4 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/Changelog b/Changelog
index 3154cf53..00722ddb 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,6 @@
+2010-03-15 Fixed the same problem in ZREVRANK
+2010-03-15 Fixed a ZRANK bug
+2010-03-15 zipmap to hash conversion in HSET
 2010-03-14 max zipmap entries and max zipmap value parameters added into INFO output
 2010-03-14 HDEL and some improvement in DEBUG OBJECT command
 2010-03-14 Append only file support for hashes
diff --git a/redis-cli.c b/redis-cli.c
index daff8701..93d80caa 100644
--- a/redis-cli.c
+++ b/redis-cli.c
@@ -148,6 +148,7 @@ static struct redisCommand cmdTable[] = {
     {"hset",4,REDIS_CMD_MULTIBULK},
     {"hget",3,REDIS_CMD_BULK},
     {"hdel",3,REDIS_CMD_BULK},
+    {"hlen",2,REDIS_CMD_INLINE},
     {NULL,0,0}
 };
 
diff --git a/redis.c b/redis.c
index c43f7fd9..46ca1655 100644
--- a/redis.c
+++ b/redis.c
@@ -682,6 +682,7 @@ static void zrevrankCommand(redisClient *c);
 static void hsetCommand(redisClient *c);
 static void hgetCommand(redisClient *c);
 static void hdelCommand(redisClient *c);
+static void hlenCommand(redisClient *c);
 static void zremrangebyrankCommand(redisClient *c);
 static void zunionCommand(redisClient *c);
 static void zinterCommand(redisClient *c);
@@ -746,6 +747,7 @@ static struct redisCommand cmdTable[] = {
     {"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,1,1,1},
     {"hget",hgetCommand,3,REDIS_CMD_BULK,1,1,1},
     {"hdel",hdelCommand,3,REDIS_CMD_BULK,1,1,1},
+    {"hlen",hlenCommand,2,REDIS_CMD_INLINE,1,1,1},
     {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,1,1,1},
     {"decrby",decrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,1,1,1},
     {"getset",getsetCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,1,1,1},
@@ -2480,6 +2482,14 @@ static void addReplyLong(redisClient *c, long l) {
     addReplySds(c,sdsnewlen(buf,len));
 }
 
+static void addReplyUlong(redisClient *c, unsigned long ul) {
+    char buf[128];
+    size_t len;
+
+    len = snprintf(buf,sizeof(buf),":%lu\r\n",ul);
+    addReplySds(c,sdsnewlen(buf,len));
+}
+
 static void addReplyBulkLen(redisClient *c, robj *obj) {
     size_t len;
 
@@ -2739,6 +2749,26 @@ static robj *lookupKeyWrite(redisDb *db, robj *key) {
     return lookupKey(db,key);
 }
 
+static robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
+    robj *o = lookupKeyRead(c->db, key);
+    if (!o) addReply(c,reply);
+    return o;
+}
+
+static robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) {
+    robj *o = lookupKeyWrite(c->db, key);
+    if (!o) addReply(c,reply);
+    return o;
+}
+
+static int checkType(redisClient *c, robj *o, int type) {
+    if (o->type != type) {
+        addReply(c,shared.wrongtypeerr);
+        return 1;
+    }
+    return 0;
+}
+
 static int deleteKey(redisDb *db, robj *key) {
     int retval;
 
@@ -6019,7 +6049,7 @@ static void hgetCommand(redisClient *c) {
 }
 
 static void hdelCommand(redisClient *c) {
-    robj *o = lookupKeyRead(c->db,c->argv[1]);
+    robj *o = lookupKeyWrite(c->db,c->argv[1]);
 
     if (o == NULL) {
         addReply(c,shared.czero);
@@ -6043,6 +6073,18 @@ static void hdelCommand(redisClient *c) {
     }
 }
 
+static void hlenCommand(redisClient *c) {
+    robj *o;
+    unsigned long len;
+
+    if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
+        checkType(c,o,REDIS_HASH)) return;
+
+    len = (o->encoding == REDIS_ENCODING_ZIPMAP) ?
+            zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
+    addReplyUlong(c,len);
+}
+
 static void convertToRealHash(robj *o) {
     unsigned char *key, *val, *p, *zm = o->ptr;
     unsigned int klen, vlen;
diff --git a/redis.tcl b/redis.tcl
index f3bf4559..ac9f8601 100644
--- a/redis.tcl
+++ b/redis.tcl
@@ -20,14 +20,14 @@ array set ::redis::multibulkarg {}
 
 # Flag commands requiring last argument as a bulk write operation
 foreach redis_bulk_cmd {
-    set setnx rpush lpush lset lrem sadd srem sismember echo getset smove zadd zrem zscore zincrby append zrank zrevrank
+    set setnx rpush lpush lset lrem sadd srem sismember echo getset smove zadd zrem zscore zincrby append zrank zrevrank hget hdel
 } {
     set ::redis::bulkarg($redis_bulk_cmd) {}
 }
 
 # Flag commands requiring last argument as a bulk write operation
 foreach redis_multibulk_cmd {
-    mset msetnx
+    mset msetnx hset
 } {
     set ::redis::multibulkarg($redis_multibulk_cmd) {}
 }
-- 
2.47.2