diff options
author | Wen Hui <wen.hui.ware@gmail.com> | 2022-02-08 06:14:42 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-08 13:14:42 +0200 |
commit | 2e1bc942aa00a76ed3b0e5e2678da4ac90071d19 (patch) | |
tree | 9b2f888fc8e0b6faee2a5e15b260be10defcec5c /src/sentinel.c | |
parent | b76016a948ecaf475ddda7958776df9bd5cf9621 (diff) | |
download | redis-2e1bc942aa00a76ed3b0e5e2678da4ac90071d19.tar.gz |
Make INFO command variadic (#6891)
This is an enhancement for INFO command, previously INFO only support one argument
for different info section , if user want to get more categories information, either perform
INFO all / default or calling INFO for multiple times.
**Description of the feature**
The goal of adding this feature is to let the user retrieve multiple categories via the INFO
command, and still avoid emitting the same section twice.
A use case for this is like Redis Sentinel, which periodically calling INFO command to refresh
info from monitored Master/Slaves, only Server and Replication part categories are used for
parsing information. If the INFO command can return just enough categories that client side
needs, it can save a lot of time for client side parsing it as well as network bandwidth.
**Implementation**
To share code between redis, sentinel, and other users of INFO (DEBUG and modules),
we have a new `genInfoSectionDict` function that returns a dict and some boolean flags
(e.g. `all`) to the caller (built from user input).
Sentinel is later purging unwanted sections from that, and then it is forwarded to the info `genRedisInfoString`.
**Usage Examples**
INFO Server Replication
INFO CPU Memory
INFO default commandstats
Co-authored-by: Oran Agra <oran@redislabs.com>
Diffstat (limited to 'src/sentinel.c')
-rw-r--r-- | src/sentinel.c | 65 |
1 files changed, 36 insertions, 29 deletions
diff --git a/src/sentinel.c b/src/sentinel.c index 98121acde..61408c802 100644 --- a/src/sentinel.c +++ b/src/sentinel.c @@ -4099,46 +4099,52 @@ numargserr: addReplyErrorArity(c); } -#define info_section_from_redis(section_name) do { \ - if (defsections || allsections || !strcasecmp(section,section_name)) { \ - sds redissection; \ - if (sections++) info = sdscat(info,"\r\n"); \ - redissection = genRedisInfoString(section_name); \ - info = sdscatlen(info,redissection,sdslen(redissection)); \ - sdsfree(redissection); \ - } \ -} while(0) +void addInfoSectionsToDict(dict *section_dict, char **sections); /* SENTINEL INFO [section] */ void sentinelInfoCommand(client *c) { - if (c->argc > 2) { - addReplyErrorObject(c,shared.syntaxerr); - return; + char *sentinel_sections[] = {"server", "clients", "cpu", "stats", "sentinel", NULL}; + int sec_all = 0, sec_everything = 0; + static dict *cached_all_info_sectoins = NULL; + + /* Get requested section list. */ + dict *sections_dict = genInfoSectionDict(c->argv+1, c->argc-1, sentinel_sections, &sec_all, &sec_everything); + + /* Purge unsupported sections from the requested ones. */ + dictEntry *de; + dictIterator *di = dictGetSafeIterator(sections_dict); + while((de = dictNext(di)) != NULL) { + int i; + sds sec = dictGetKey(de); + for (i=0; sentinel_sections[i]; i++) + if (!strcasecmp(sentinel_sections[i], sec)) + break; + /* section not found? remove it */ + if (!sentinel_sections[i]) + dictDelete(sections_dict, sec); } + dictReleaseIterator(di); - int defsections = 0, allsections = 0; - char *section = c->argc == 2 ? c->argv[1]->ptr : NULL; - if (section) { - allsections = !strcasecmp(section,"all"); - defsections = !strcasecmp(section,"default"); - } else { - defsections = 1; + /* Insert explicit all sections (don't pass these vars to genRedisInfoString) */ + if (sec_all || sec_everything) { + releaseInfoSectionDict(sections_dict); + /* We cache this dict as an optimization. */ + if (!cached_all_info_sectoins) { + cached_all_info_sectoins = dictCreate(&stringSetDictType); + addInfoSectionsToDict(cached_all_info_sectoins, sentinel_sections); + } + sections_dict = cached_all_info_sectoins; } - int sections = 0; sds info = sdsempty(); - - info_section_from_redis("server"); - info_section_from_redis("clients"); - info_section_from_redis("cpu"); - info_section_from_redis("stats"); - - if (defsections || allsections || !strcasecmp(section,"sentinel")) { + info = genRedisInfoString(sections_dict, 0, 0); + if (sec_all || (dictFind(sections_dict, "sentinel") != NULL)) { dictIterator *di; dictEntry *de; int master_id = 0; - if (sections++) info = sdscat(info,"\r\n"); + if (sdslen(info) != 0) + info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Sentinel\r\n" "sentinel_masters:%lu\r\n" @@ -4171,7 +4177,8 @@ void sentinelInfoCommand(client *c) { } dictReleaseIterator(di); } - + if (sections_dict != cached_all_info_sectoins) + releaseInfoSectionDict(sections_dict); addReplyBulkSds(c, info); } |