From e8901b2fe489013b17e943d2721f961a50bda07c Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" <zhaozhao.zz@alibaba-inc.com> Date: Fri, 8 Dec 2017 15:37:08 +0800 Subject: [PATCH 1/8] zset: fix the int problem --- src/server.h | 2 +- src/t_zset.c | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/server.h b/src/server.h index ee3b7df5..9917c1f8 100644 --- a/src/server.h +++ b/src/server.h @@ -1590,7 +1590,7 @@ void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr); void zzlPrev(unsigned char *zl, unsigned char **eptr, unsigned char **sptr); unsigned char *zzlFirstInRange(unsigned char *zl, zrangespec *range); unsigned char *zzlLastInRange(unsigned char *zl, zrangespec *range); -unsigned int zsetLength(const robj *zobj); +unsigned long zsetLength(const robj *zobj); void zsetConvert(robj *zobj, int encoding); void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen); int zsetScore(robj *zobj, sds member, double *score); diff --git a/src/t_zset.c b/src/t_zset.c index f7f4c6eb..cfd5f2b9 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -1100,8 +1100,8 @@ unsigned char *zzlDeleteRangeByRank(unsigned char *zl, unsigned int start, unsig * Common sorted set API *----------------------------------------------------------------------------*/ -unsigned int zsetLength(const robj *zobj) { - int length = -1; +unsigned long zsetLength(const robj *zobj) { + unsigned long length = 0; if (zobj->encoding == OBJ_ENCODING_ZIPLIST) { length = zzlLength(zobj->ptr); } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) { @@ -1878,7 +1878,7 @@ void zuiClearIterator(zsetopsrc *op) { } } -int zuiLength(zsetopsrc *op) { +unsigned long zuiLength(zsetopsrc *op) { if (op->subject == NULL) return 0; @@ -2085,7 +2085,11 @@ int zuiFind(zsetopsrc *op, zsetopval *val, double *score) { } int zuiCompareByCardinality(const void *s1, const void *s2) { - return zuiLength((zsetopsrc*)s1) - zuiLength((zsetopsrc*)s2); + unsigned long first = zuiLength((zsetopsrc*)s1); + unsigned long second = zuiLength((zsetopsrc*)s2); + if (first > second) return 1; + if (first < second) return -1; + return 0; } #define REDIS_AGGR_SUM 1 @@ -2129,7 +2133,7 @@ void zunionInterGenericCommand(client *c, robj *dstkey, int op) { zsetopsrc *src; zsetopval zval; sds tmp; - unsigned int maxelelen = 0; + size_t maxelelen = 0; robj *dstobj; zset *dstzset; zskiplistNode *znode; @@ -2363,8 +2367,8 @@ void zrangeGenericCommand(client *c, int reverse) { int withscores = 0; long start; long end; - int llen; - int rangelen; + long llen; + long rangelen; if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) || (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return; @@ -2671,7 +2675,7 @@ void zcountCommand(client *c) { robj *key = c->argv[1]; robj *zobj; zrangespec range; - int count = 0; + unsigned long count = 0; /* Parse the range arguments */ if (zslParseRange(c->argv[2],c->argv[3],&range) != C_OK) { @@ -2748,7 +2752,7 @@ void zlexcountCommand(client *c) { robj *key = c->argv[1]; robj *zobj; zlexrangespec range; - int count = 0; + unsigned long count = 0; /* Parse the range arguments */ if (zslParseLexRange(c->argv[2],c->argv[3],&range) != C_OK) { From 109ee497be24906e7931d33b71e3a6e78c5de77b Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" <zhaozhao.zz@alibaba-inc.com> Date: Fri, 8 Dec 2017 16:09:27 +0800 Subject: [PATCH 2/8] zset: change the span of zskiplistNode to unsigned long --- src/server.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server.h b/src/server.h index 9917c1f8..f3a97065 100644 --- a/src/server.h +++ b/src/server.h @@ -335,7 +335,7 @@ typedef long long mstime_t; /* millisecond time type. */ /* Anti-warning macro... */ #define UNUSED(V) ((void) V) -#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */ +#define ZSKIPLIST_MAXLEVEL 64 /* Should be enough for 2^64 elements */ #define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */ /* Append only defines */ @@ -774,7 +774,7 @@ typedef struct zskiplistNode { struct zskiplistNode *backward; struct zskiplistLevel { struct zskiplistNode *forward; - unsigned int span; + unsigned long span; } level[]; } zskiplistNode; From 83cf0e3668f61a57bbaaedf47d35d8943352d893 Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" <zhaozhao.zz@alibaba-inc.com> Date: Thu, 29 Mar 2018 17:36:15 +0800 Subject: [PATCH 3/8] adjust position of _dictNextPower in dictExpand --- src/dict.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dict.c b/src/dict.c index 97e63680..a7b77aad 100644 --- a/src/dict.c +++ b/src/dict.c @@ -146,14 +146,14 @@ int dictResize(dict *d) /* Expand or create the hash table */ int dictExpand(dict *d, unsigned long size) { - dictht n; /* the new hash table */ - unsigned long realsize = _dictNextPower(size); - /* the size is invalid if it is smaller than the number of * elements already inside the hash table */ if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; + dictht n; /* the new hash table */ + unsigned long realsize = _dictNextPower(size); + /* Rehashing to the same table size is not useful. */ if (realsize == d->ht[0].size) return DICT_ERR; From 24036b4d32d857066a2ccfc6cef2e8a751634ad5 Mon Sep 17 00:00:00 2001 From: "zhaozhao.zz" <zhaozhao.zz@alibaba-inc.com> Date: Sun, 22 Apr 2018 22:30:44 +0800 Subject: [PATCH 4/8] RDB: expand dict if needed when rdb load object --- src/rdb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rdb.c b/src/rdb.c index 27c3aa78..639be1ea 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -1427,6 +1427,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { o = createZsetObject(); zs = o->ptr; + if (zsetlen > DICT_HT_INITIAL_SIZE) + dictExpand(zs->dict,zsetlen); + /* Load every single element of the sorted set. */ while(zsetlen--) { sds sdsele; @@ -1495,6 +1498,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { sdsfree(value); } + if (o->encoding == OBJ_ENCODING_HT && len > DICT_HT_INITIAL_SIZE) + dictExpand(o->ptr,len); + /* Load remaining fields and values into the hash table */ while (o->encoding == OBJ_ENCODING_HT && len > 0) { len--; From 1749fe7a26e6ce53ab90271aa807380bd9458d3a Mon Sep 17 00:00:00 2001 From: michael-grunder <michael.grunder@gmail.com> Date: Sat, 2 Jun 2018 18:22:20 -0700 Subject: [PATCH 5/8] Return early in XPENDING if sent a nonexistent consumer group. --- src/t_stream.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/t_stream.c b/src/t_stream.c index 6cbef56c..ebcf1a55 100644 --- a/src/t_stream.c +++ b/src/t_stream.c @@ -1728,8 +1728,10 @@ void xpendingCommand(client *c) { /* If a consumer name was mentioned but it does not exist, we can * just return an empty array. */ - if (consumername && consumer == NULL) + if (consumername && consumer == NULL) { addReplyMultiBulkLen(c,0); + return; + } rax *pel = consumer ? consumer->pel : group->pel; unsigned char startkey[sizeof(streamID)]; From b2fc2eaecb85b34a12c2b6a4db91fa5fc466870b Mon Sep 17 00:00:00 2001 From: antirez <antirez@gmail.com> Date: Thu, 7 Jun 2018 18:52:01 +0200 Subject: [PATCH 6/8] Add the stream group to the script generating the help. --- utils/generate-command-help.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/generate-command-help.rb b/utils/generate-command-help.rb index f3dfb31b..29acef69 100755 --- a/utils/generate-command-help.rb +++ b/utils/generate-command-help.rb @@ -14,7 +14,8 @@ GROUPS = [ "scripting", "hyperloglog", "cluster", - "geo" + "geo", + "stream" ].freeze GROUPS_BY_NAME = Hash[* From 2268d7e5dd3a44a95f0e44ffe1afccebd8264b64 Mon Sep 17 00:00:00 2001 From: antirez <antirez@gmail.com> Date: Thu, 7 Jun 2018 18:53:00 +0200 Subject: [PATCH 7/8] redis-cli inline help updated. --- src/help.h | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/src/help.h b/src/help.h index 5f927c30..005afd94 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 @@ -17,7 +17,8 @@ static char *commandGroups[] = { "scripting", "hyperloglog", "cluster", - "geo" + "geo", + "stream" }; struct commandHelp { @@ -82,6 +83,16 @@ struct commandHelp { "Pop a value from a list, push it to another list and return it; or block until one is available", 2, "2.2.0" }, + { "BZPOPMAX", + "key [key ...] timeout", + "Remove and return the member with the highest score from one or more sorted sets, or block until one is available", + 4, + "5.0.0" }, + { "BZPOPMIN", + "key [key ...] timeout", + "Remove and return the member with the lowest score from one or more sorted sets, or block until one is available", + 4, + "5.0.0" }, { "CLIENT GETNAME", "-", "Get the current connection name", @@ -318,12 +329,12 @@ struct commandHelp { 0, "1.2.0" }, { "FLUSHALL", - "-", + "[ASYNC]", "Remove all keys from all databases", 9, "1.0.0" }, { "FLUSHDB", - "-", + "[ASYNC]", "Remove all keys from the current database", 9, "1.0.0" }, @@ -532,6 +543,36 @@ struct commandHelp { "Trim a list to the specified range", 2, "1.0.0" }, + { "MEMORY DOCTOR", + "-", + "Outputs memory problems report", + 9, + "4.0.0" }, + { "MEMORY HELP", + "-", + "Show helpful text about the different subcommands", + 9, + "4.0.0" }, + { "MEMORY MALLOC-STATS", + "-", + "Show allocator internal stats", + 9, + "4.0.0" }, + { "MEMORY PURGE", + "-", + "Ask the allocator to release memory", + 9, + "4.0.0" }, + { "MEMORY STATS", + "-", + "Show memory usage details", + 9, + "4.0.0" }, + { "MEMORY USAGE", + "key [SAMPLES count]", + "Estimate the memory usage of a key", + 9, + "4.0.0" }, { "MGET", "key [key ...]", "Get the values of all the given keys", @@ -723,7 +764,7 @@ struct commandHelp { 10, "3.2.0" }, { "SCRIPT EXISTS", - "script [script ...]", + "sha1 [sha1 ...]", "Check existence of scripts in the script cache.", 10, "2.6.0" }, @@ -758,7 +799,7 @@ struct commandHelp { 8, "1.0.0" }, { "SET", - "key value [EX seconds] [PX milliseconds] [NX|XX]", + "key value [expiration EX seconds|PX milliseconds] [NX|XX]", "Set the string value of a key", 1, "1.0.0" }, @@ -867,6 +908,11 @@ struct commandHelp { "Add multiple sets and store the resulting set in a key", 3, "1.0.0" }, + { "SWAPDB", + "index index", + "Swaps two Redis databases", + 8, + "4.0.0" }, { "SYNC", "-", "Internal command used for replication", @@ -877,6 +923,11 @@ struct commandHelp { "Return the current server time", 9, "2.6.0" }, + { "TOUCH", + "key [key ...]", + "Alters the last access time of a key(s). Returns the number of existing keys specified.", + 0, + "3.2.1" }, { "TTL", "key", "Get the time to live for a key", @@ -887,6 +938,11 @@ struct commandHelp { "Determine the type stored at key", 0, "1.0.0" }, + { "UNLINK", + "key [key ...]", + "Delete a key asynchronously in another thread. Otherwise it is just as DEL, but non blocking.", + 0, + "4.0.0" }, { "UNSUBSCRIBE", "[channel [channel ...]]", "Stop listening for messages posted to the given channels", @@ -907,6 +963,41 @@ struct commandHelp { "Watch the given keys to determine execution of the MULTI/EXEC block", 7, "2.2.0" }, + { "XADD", + "key ID field string [field string ...]", + "Appends a new entry to a stream", + 14, + "5.0.0" }, + { "XLEN", + "key", + "Return the number of entires in a stream", + 14, + "5.0.0" }, + { "XPENDING", + "key group [start end count] [consumer]", + "Return information and entries from a stream conusmer group pending entries list, that are messages fetched but never acknowledged.", + 14, + "5.0.0" }, + { "XRANGE", + "key start end [COUNT count]", + "Return a range of elements in a stream, with IDs matching the specified IDs interval", + 14, + "5.0.0" }, + { "XREAD", + "[COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]", + "Return never seen elements in multiple streams, with IDs greater than the ones reported by the caller for each stream. Can block.", + 14, + "5.0.0" }, + { "XREADGROUP", + "GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]", + "Return new entries from a stream using a consumer group, or access the history of the pending entries for a given consumer. Can block.", + 14, + "5.0.0" }, + { "XREVRANGE", + "key end start [COUNT count]", + "Return a range of elements in a stream, with IDs matching the specified IDs interval, in reverse order (from greater to smaller IDs) compared to XRANGE", + 14, + "5.0.0" }, { "ZADD", "key [NX|XX] [CH] [INCR] score member [score member ...]", "Add one or more members to a sorted set, or update its score if it already exists", @@ -937,6 +1028,16 @@ struct commandHelp { "Count the number of members in a sorted set between a given lexicographical range", 4, "2.8.9" }, + { "ZPOPMAX", + "key [count]", + "Remove and return members with the highest scores in a sorted set", + 4, + "5.0.0" }, + { "ZPOPMIN", + "key [count]", + "Remove and return members with the lowest scores in a sorted set", + 4, + "5.0.0" }, { "ZRANGE", "key start stop [WITHSCORES]", "Return a range of members in a sorted set, by index", From 269e80526f1f90142661b9e25bff3a08639ce59c Mon Sep 17 00:00:00 2001 From: antirez <antirez@gmail.com> Date: Fri, 8 Jun 2018 11:17:20 +0200 Subject: [PATCH 8/8] Implement DEBUG htstats-key. --- src/debug.c | 29 +++++++++++++++++++++++++++++ src/redis-cli.c | 2 ++ 2 files changed, 31 insertions(+) diff --git a/src/debug.c b/src/debug.c index 0ab864e7..078ac3c6 100644 --- a/src/debug.c +++ b/src/debug.c @@ -290,6 +290,7 @@ void debugCommand(client *c) { "crash-and-recover <milliseconds> -- Hard crash and restart after <milliseconds> delay.", "digest -- Outputs an hex signature representing the current DB content.", "htstats <dbid> -- Return hash table statistics of the specified Redis database.", +"htstats-key <key> -- Like htstats but for the hash table stored as key's value.", "loadaof -- Flush the AOF buffers on disk and reload the AOF in memory.", "lua-always-replicate-commands (0|1) -- Setting it to 1 makes Lua replication defaulting to replicating single commands, without the script having to enable effects replication.", "object <key> -- Show low level info about key and associated value.", @@ -547,6 +548,34 @@ NULL stats = sdscat(stats,buf); addReplyBulkSds(c,stats); + } else if (!strcasecmp(c->argv[1]->ptr,"htstats-key") && c->argc == 3) { + robj *o; + dict *ht = NULL; + + if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nokeyerr)) + == NULL) return; + + /* Get the hash table reference from the object, if possible. */ + switch (o->encoding) { + case OBJ_ENCODING_SKIPLIST: + { + zset *zs = o->ptr; + ht = zs->dict; + } + break; + case OBJ_ENCODING_HT: + ht = o->ptr; + break; + } + + if (ht == NULL) { + addReplyError(c,"The value stored at the specified key is not " + "represented using an hash table"); + } else { + char buf[4096]; + dictGetStats(buf,sizeof(buf),ht); + addReplyBulkCString(c,buf); + } } else if (!strcasecmp(c->argv[1]->ptr,"change-repl-id") && c->argc == 2) { serverLog(LL_WARNING,"Changing replication IDs after receiving DEBUG change-repl-id"); changeReplicationId(); diff --git a/src/redis-cli.c b/src/redis-cli.c index 0ee9f84e..af5e6a23 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1075,6 +1075,8 @@ static int cliSendCommand(int argc, char **argv, long repeat) { if (!strcasecmp(command,"info") || (argc >= 2 && !strcasecmp(command,"debug") && !strcasecmp(argv[1],"htstats")) || + (argc >= 2 && !strcasecmp(command,"debug") && + !strcasecmp(argv[1],"htstats-key")) || (argc >= 2 && !strcasecmp(command,"memory") && (!strcasecmp(argv[1],"malloc-stats") || !strcasecmp(argv[1],"doctor"))) ||