From 9d7165e885b3de44577dea2917bb4f3afa2ed335 Mon Sep 17 00:00:00 2001
From: antirez <antirez@gmail.com>
Date: Sun, 19 Dec 2010 12:22:12 +0100
Subject: [PATCH 1/3] overflow detection in INCR family functions

---
 src/t_string.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/t_string.c b/src/t_string.c
index eb080c882..c3e3607f3 100644
--- a/src/t_string.c
+++ b/src/t_string.c
@@ -346,14 +346,19 @@ void msetnxCommand(redisClient *c) {
 }
 
 void incrDecrCommand(redisClient *c, long long incr) {
-    long long value;
+    long long value, oldvalue;
     robj *o;
 
     o = lookupKeyWrite(c->db,c->argv[1]);
     if (o != NULL && checkType(c,o,REDIS_STRING)) return;
     if (getLongLongFromObjectOrReply(c,o,&value,NULL) != REDIS_OK) return;
 
+    oldvalue = value;
     value += incr;
+    if ((incr < 0 && value > oldvalue) || (incr > 0 && value < oldvalue)) {
+        addReplyError(c,"increment or decrement would overflow");
+        return;
+    }
     o = createStringObjectFromLongLong(value);
     dbReplace(c->db,c->argv[1],o);
     touchWatchedKey(c->db,c->argv[1]);

From f21779ff36947fe22e6fc3f00d4bd73185557190 Mon Sep 17 00:00:00 2001
From: antirez <antirez@gmail.com>
Date: Sun, 19 Dec 2010 15:15:08 +0100
Subject: [PATCH 2/3] removed some dead code, added evicted keys counter
 separated from expired keys.

---
 src/redis.c | 36 ++++--------------------------------
 src/redis.h |  1 +
 2 files changed, 5 insertions(+), 32 deletions(-)

diff --git a/src/redis.c b/src/redis.c
index fb6eb4694..6e667f29a 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -891,6 +891,7 @@ void initServer() {
     server.stat_numcommands = 0;
     server.stat_numconnections = 0;
     server.stat_expiredkeys = 0;
+    server.stat_evictedkeys = 0;
     server.stat_starttime = time(NULL);
     server.stat_keyspace_misses = 0;
     server.stat_keyspace_hits = 0;
@@ -1177,6 +1178,7 @@ sds genRedisInfoString(void) {
         "total_connections_received:%lld\r\n"
         "total_commands_processed:%lld\r\n"
         "expired_keys:%lld\r\n"
+        "evicted_keys:%lld\r\n"
         "keyspace_hits:%lld\r\n"
         "keyspace_misses:%lld\r\n"
         "hash_max_zipmap_entries:%zu\r\n"
@@ -1219,6 +1221,7 @@ sds genRedisInfoString(void) {
         server.stat_numconnections,
         server.stat_numcommands,
         server.stat_expiredkeys,
+        server.stat_evictedkeys,
         server.stat_keyspace_hits,
         server.stat_keyspace_misses,
         server.hash_max_zipmap_entries,
@@ -1436,44 +1439,13 @@ void freeMemoryIfNeeded(void) {
             if (bestkey) {
                 robj *keyobj = createStringObject(bestkey,sdslen(bestkey));
                 dbDelete(db,keyobj);
-                server.stat_expiredkeys++;
+                server.stat_evictedkeys++;
                 decrRefCount(keyobj);
                 freed++;
             }
         }
         if (!freed) return; /* nothing to free... */
     }
-
-    while(0) {
-        int j, k, freed = 0;
-        for (j = 0; j < server.dbnum; j++) {
-            int minttl = -1;
-            sds minkey = NULL;
-            robj *keyobj = NULL;
-            struct dictEntry *de;
-
-            if (dictSize(server.db[j].expires)) {
-                freed = 1;
-                /* From a sample of three keys drop the one nearest to
-                 * the natural expire */
-                for (k = 0; k < 3; k++) {
-                    time_t t;
-
-                    de = dictGetRandomKey(server.db[j].expires);
-                    t = (time_t) dictGetEntryVal(de);
-                    if (minttl == -1 || t < minttl) {
-                        minkey = dictGetEntryKey(de);
-                        minttl = t;
-                    }
-                }
-                keyobj = createStringObject(minkey,sdslen(minkey));
-                dbDelete(server.db+j,keyobj);
-                server.stat_expiredkeys++;
-                decrRefCount(keyobj);
-            }
-        }
-        if (!freed) return; /* nothing to free... */
-    }
 }
 
 /* =================================== Main! ================================ */
diff --git a/src/redis.h b/src/redis.h
index 8495a87e5..bc1a58c17 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -387,6 +387,7 @@ struct redisServer {
     long long stat_numcommands;     /* number of processed commands */
     long long stat_numconnections;  /* number of connections received */
     long long stat_expiredkeys;     /* number of expired keys */
+    long long stat_evictedkeys;     /* number of evicted keys (maxmemory) */
     long long stat_keyspace_hits;   /* number of successful lookups of keys */
     long long stat_keyspace_misses; /* number of failed lookups of keys */
     /* Configuration */

From 180596766bb48698fda28069ae5028554caac74c Mon Sep 17 00:00:00 2001
From: antirez <antirez@gmail.com>
Date: Wed, 15 Dec 2010 17:39:40 +0100
Subject: [PATCH 3/3] help.h updated

---
 src/help.h                     | 54 ++++++++++++++++++++++++++--------
 utils/generate-command-help.rb |  1 +
 2 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/src/help.h b/src/help.h
index 121d9dfaf..51613c9b3 100644
--- a/src/help.h
+++ b/src/help.h
@@ -1,4 +1,4 @@
-/* Automatically generated by utils/generate-command-help.rb, do not edit. */
+/* Automatically generated by generate-command-help.rb, do not edit. */
 
 #ifndef __REDIS_HELP_H
 #define __REDIS_HELP_H
@@ -53,11 +53,21 @@ struct commandHelp {
     "Remove and get the last element in a list, or block until one is available",
     2,
     "1.3.1" },
+    { "BRPOPLPUSH",
+    "source destination timeout",
+    "Pop a value from a list, push it to another list and return it; or block until one is available",
+    2,
+    "2.1.7" },
     { "CONFIG GET",
     "parameter",
     "Get the value of a configuration parameter",
     9,
     "2.0" },
+    { "CONFIG RESETSTAT",
+    "-",
+    "Reset the stats returned by INFO",
+    9,
+    "2.0" },
     { "CONFIG SET",
     "parameter value",
     "Set a configuration parameter to the given value",
@@ -79,7 +89,7 @@ struct commandHelp {
     9,
     "0.101" },
     { "DECR",
-    "key decrement",
+    "key",
     "Decrement the integer value of a key by one",
     1,
     "0.07" },
@@ -138,6 +148,11 @@ struct commandHelp {
     "Get the value of a key",
     1,
     "0.07" },
+    { "GETBIT",
+    "key offset",
+    "Returns the bit value at offset in the string value stored at key",
+    1,
+    "2.1.8" },
     { "GETSET",
     "key value",
     "Set the string value of a key and return its old value",
@@ -344,12 +359,12 @@ struct commandHelp {
     0,
     "0.07" },
     { "RENAME",
-    "old new",
+    "key newkey",
     "Rename a key",
     0,
     "0.07" },
     { "RENAMENX",
-    "old new",
+    "key newkey",
     "Rename a key, only if the new key does not exist",
     0,
     "0.07" },
@@ -408,8 +423,13 @@ struct commandHelp {
     "Set the string value of a key",
     1,
     "0.07" },
+    { "SETBIT",
+    "key offset value",
+    "Sets or clears the bit at offset in the string value stored at key",
+    1,
+    "2.1.8" },
     { "SETEX",
-    "key timestamp value",
+    "key seconds value",
     "Set the value and expiration of a key",
     1,
     "1.3.10" },
@@ -418,6 +438,11 @@ struct commandHelp {
     "Set the value of a key, only if the key does not exist",
     1,
     "0.07" },
+    { "SETRANGE",
+    "key offset value",
+    "Overwrite part of a string at key starting at the specified offset",
+    1,
+    "2.1.8" },
     { "SHUTDOWN",
     "-",
     "Synchronously save the dataset to disk and then shut down the server",
@@ -454,7 +479,7 @@ struct commandHelp {
     3,
     "0.091" },
     { "SORT",
-    "key [BY pattern] [LIMIT start count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
+    "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
     "Sort the elements in a list, set or sorted set",
     0,
     "0.07" },
@@ -484,7 +509,7 @@ struct commandHelp {
     6,
     "1.3.8" },
     { "SUBSTR",
-    "key start stop",
+    "key start end",
     "Get a substring of the string stored at a key",
     1,
     "1.3.4" },
@@ -549,17 +574,17 @@ struct commandHelp {
     4,
     "1.1" },
     { "ZINTERSTORE",
-    "destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
+    "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
     "Intersect multiple sorted sets and store the resulting sorted set in a new key",
     4,
     "1.3.10" },
     { "ZRANGE",
-    "key start stop",
+    "key start stop [WITHSCORES]",
     "Return a range of members in a sorted set, by index",
     4,
     "1.1" },
     { "ZRANGEBYSCORE",
-    "key min max",
+    "key min max [WITHSCORES] [LIMIT offset count]",
     "Return a range of members in a sorted set, by score",
     4,
     "1.050" },
@@ -584,10 +609,15 @@ struct commandHelp {
     4,
     "1.1" },
     { "ZREVRANGE",
-    "key start stop",
+    "key start stop [WITHSCORES]",
     "Return a range of members in a sorted set, by index, with scores ordered from high to low",
     4,
     "1.1" },
+    { "ZREVRANGEBYSCORE",
+    "key max min [WITHSCORES] [LIMIT offset count]",
+    "Return a range of members in a sorted set, by score, with scores ordered from high to low",
+    4,
+    "2.1.6" },
     { "ZREVRANK",
     "key member",
     "Determine the index of a member in a sorted set, with scores ordered from high to low",
@@ -599,7 +629,7 @@ struct commandHelp {
     4,
     "1.1" },
     { "ZUNIONSTORE",
-    "destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
+    "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
     "Add multiple sorted sets and store the resulting sorted set in a new key",
     4,
     "1.3.10" }
diff --git a/utils/generate-command-help.rb b/utils/generate-command-help.rb
index f730eaf10..96cccc2bf 100755
--- a/utils/generate-command-help.rb
+++ b/utils/generate-command-help.rb
@@ -42,6 +42,7 @@ end
 def commands
   return @commands if @commands
 
+  require "rubygems"
   require "net/http"
   require "net/https"
   require "json"