diff options
-rw-r--r-- | src/config.c | 7 | ||||
-rw-r--r-- | src/module.c | 14 | ||||
-rw-r--r-- | src/redismodule.h | 1 | ||||
-rw-r--r-- | tests/modules/moduleconfigs.c | 24 | ||||
-rw-r--r-- | tests/unit/moduleapi/moduleconfigs.tcl | 12 |
5 files changed, 51 insertions, 7 deletions
diff --git a/src/config.c b/src/config.c index 805aececb..0d435fecb 100644 --- a/src/config.c +++ b/src/config.c @@ -547,12 +547,15 @@ void loadServerConfigFromString(char *config) { } else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) { queueLoadModule(argv[1],&argv[2],argc-2); } else if (strchr(argv[0], '.')) { - if (argc != 2) { + if (argc < 2) { err = "Module config specified without value"; goto loaderr; } sds name = sdsdup(argv[0]); - if (!dictReplace(server.module_configs_queue, name, sdsdup(argv[1]))) sdsfree(name); + sds val = sdsdup(argv[1]); + for (int i = 2; i < argc; i++) + val = sdscatfmt(val, " %S", argv[i]); + if (!dictReplace(server.module_configs_queue, name, val)) sdsfree(name); } else if (!strcasecmp(argv[0],"sentinel")) { /* argc == 1 is handled by main() as we need to enter the sentinel * mode ASAP. */ diff --git a/src/module.c b/src/module.c index a1e104c0d..99d2adcd4 100644 --- a/src/module.c +++ b/src/module.c @@ -11325,6 +11325,7 @@ int moduleVerifyConfigFlags(unsigned int flags, configType type) { | REDISMODULE_CONFIG_HIDDEN | REDISMODULE_CONFIG_PROTECTED | REDISMODULE_CONFIG_DENY_LOADING + | REDISMODULE_CONFIG_BITFLAGS | REDISMODULE_CONFIG_MEMORY))) { serverLogRaw(LL_WARNING, "Invalid flag(s) for configuration"); return REDISMODULE_ERR; @@ -11333,6 +11334,10 @@ int moduleVerifyConfigFlags(unsigned int flags, configType type) { serverLogRaw(LL_WARNING, "Numeric flag provided for non-numeric configuration."); return REDISMODULE_ERR; } + if (type != ENUM_CONFIG && flags & REDISMODULE_CONFIG_BITFLAGS) { + serverLogRaw(LL_WARNING, "Enum flag provided for non-enum configuration."); + return REDISMODULE_ERR; + } return REDISMODULE_OK; } @@ -11534,6 +11539,12 @@ unsigned int maskModuleNumericConfigFlags(unsigned int flags) { return new_flags; } +unsigned int maskModuleEnumConfigFlags(unsigned int flags) { + unsigned int new_flags = 0; + if (flags & REDISMODULE_CONFIG_BITFLAGS) new_flags |= MULTI_ARG_CONFIG; + return new_flags; +} + /* Create a string config that Redis users can interact with via the Redis config file, * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. * @@ -11573,6 +11584,7 @@ unsigned int maskModuleNumericConfigFlags(unsigned int flags) { * * REDISMODULE_CONFIG_PROTECTED: This config will be only be modifiable based off the value of enable-protected-configs. * * REDISMODULE_CONFIG_DENY_LOADING: This config is not modifiable while the server is loading data. * * REDISMODULE_CONFIG_MEMORY: For numeric configs, this config will convert data unit notations into their byte equivalent. + * * REDISMODULE_CONFIG_BITFLAGS: For enum configs, this config will allow multiple entries to be combined as bit flags. * * Default values are used on startup to set the value if it is not provided via the config file * or command line. Default values are also used to compare to on a config rewrite. @@ -11688,7 +11700,7 @@ int RM_RegisterEnumConfig(RedisModuleCtx *ctx, const char *name, int default_val enum_vals[num_enum_vals].name = NULL; enum_vals[num_enum_vals].val = 0; listAddNodeTail(module->module_configs, new_config); - flags = maskModuleConfigFlags(flags); + flags = maskModuleConfigFlags(flags) | maskModuleEnumConfigFlags(flags); addModuleEnumConfig(module->name, name, flags, new_config, default_val, enum_vals); return REDISMODULE_OK; } diff --git a/src/redismodule.h b/src/redismodule.h index e72f5f7bc..cd389dd00 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -88,6 +88,7 @@ #define REDISMODULE_CONFIG_DENY_LOADING (1ULL<<6) /* This config is forbidden during loading. */ #define REDISMODULE_CONFIG_MEMORY (1ULL<<7) /* Indicates if this value can be set as a memory value */ +#define REDISMODULE_CONFIG_BITFLAGS (1ULL<<8) /* Indicates if this value can be set as a multiple enum values */ /* StreamID type. */ typedef struct RedisModuleStreamID { diff --git a/tests/modules/moduleconfigs.c b/tests/modules/moduleconfigs.c index af30bda34..0a6380461 100644 --- a/tests/modules/moduleconfigs.c +++ b/tests/modules/moduleconfigs.c @@ -6,6 +6,7 @@ long long longval; long long memval; RedisModuleString *strval = NULL; int enumval; +int flagsval; /* Series of get and set callbacks for each type of config, these rely on the privdata ptr * to point to the config, and they register the configs as such. Note that one could also just @@ -68,6 +69,20 @@ int setEnumConfigCommand(const char *name, int val, void *privdata, RedisModuleS return REDISMODULE_OK; } +int getFlagsConfigCommand(const char *name, void *privdata) { + REDISMODULE_NOT_USED(name); + REDISMODULE_NOT_USED(privdata); + return flagsval; +} + +int setFlagsConfigCommand(const char *name, int val, void *privdata, RedisModuleString **err) { + REDISMODULE_NOT_USED(name); + REDISMODULE_NOT_USED(err); + REDISMODULE_NOT_USED(privdata); + flagsval = val; + return REDISMODULE_OK; +} + int boolApplyFunc(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err) { REDISMODULE_NOT_USED(ctx); REDISMODULE_NOT_USED(privdata); @@ -106,10 +121,13 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) } /* On the stack to make sure we're copying them. */ - const char *enum_vals[3] = {"one", "two", "three"}; - const int int_vals[3] = {0, 2, 4}; + const char *enum_vals[] = {"none", "one", "two", "three"}; + const int int_vals[] = {0, 1, 2, 4}; - if (RedisModule_RegisterEnumConfig(ctx, "enum", 0, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 3, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) { + if (RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 4, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } + if (RedisModule_RegisterEnumConfig(ctx, "flags", 3, REDISMODULE_CONFIG_DEFAULT | REDISMODULE_CONFIG_BITFLAGS, enum_vals, int_vals, 4, getFlagsConfigCommand, setFlagsConfigCommand, NULL, NULL) == REDISMODULE_ERR) { return REDISMODULE_ERR; } /* Memory config here. */ diff --git a/tests/unit/moduleapi/moduleconfigs.tcl b/tests/unit/moduleapi/moduleconfigs.tcl index 29682d2e2..f731d1bd9 100644 --- a/tests/unit/moduleapi/moduleconfigs.tcl +++ b/tests/unit/moduleapi/moduleconfigs.tcl @@ -11,6 +11,7 @@ start_server {tags {"modules"}} { assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024" assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {secret password}" assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum one" + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {one two}" assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1" } @@ -29,6 +30,10 @@ start_server {tags {"modules"}} { assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {super \0secret password}" r config set moduleconfigs.enum two assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum two" + r config set moduleconfigs.flags two + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags two" + r config set moduleconfigs.flags "two three" + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {two three}" r config set moduleconfigs.numeric -2 assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -2" } @@ -67,6 +72,7 @@ start_server {tags {"modules"}} { assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024" assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {secret password}" assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum one" + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {one two}" assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1" r module unload moduleconfigs } @@ -80,6 +86,7 @@ start_server {tags {"modules"}} { assert_equal [r config get moduleconfigs.string] "moduleconfigs.string tclortickle" # Configs that were not changed should still be their module specified value assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum one" + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {one two}" assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1" } @@ -140,6 +147,7 @@ start_server {tags {"modules"}} { r config set moduleconfigs.mutable_bool yes r config set moduleconfigs.memory_numeric 750 r config set moduleconfigs.enum two + r config set moduleconfigs.flags "two three" r config rewrite restart_server 0 true false # Ensure configs we rewrote are present and that the conf file is readable @@ -147,6 +155,7 @@ start_server {tags {"modules"}} { assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 750" assert_equal [r config get moduleconfigs.string] "moduleconfigs.string {super \0secret password}" assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum two" + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {two three}" assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1" r module unload moduleconfigs } @@ -221,11 +230,12 @@ start_server {tags {"modules"}} { set stdout [dict get $noload stdout] assert_equal [count_message_lines $stdout "Module Configurations were not set, likely a missing LoadConfigs call. Unloading the module."] 1 - start_server [list overrides [list loadmodule "$testmodule" moduleconfigs.string "bootedup" moduleconfigs.enum two]] { + start_server [list overrides [list loadmodule "$testmodule" moduleconfigs.string "bootedup" moduleconfigs.enum two moduleconfigs.flags "two three"]] { assert_equal [r config get moduleconfigs.string] "moduleconfigs.string bootedup" assert_equal [r config get moduleconfigs.mutable_bool] "moduleconfigs.mutable_bool yes" assert_equal [r config get moduleconfigs.immutable_bool] "moduleconfigs.immutable_bool no" assert_equal [r config get moduleconfigs.enum] "moduleconfigs.enum two" + assert_equal [r config get moduleconfigs.flags] "moduleconfigs.flags {two three}" assert_equal [r config get moduleconfigs.numeric] "moduleconfigs.numeric -1" assert_equal [r config get moduleconfigs.memory_numeric] "moduleconfigs.memory_numeric 1024" } |