-
Notifications
You must be signed in to change notification settings - Fork 653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add API UpdateRuntimeArgs to allow the module arguments during runtime and save the new arguments value into the conf file #1041
base: unstable
Are you sure you want to change the base?
Conversation
c52d35c
to
c3341b1
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## unstable #1041 +/- ##
============================================
+ Coverage 70.65% 70.69% +0.03%
============================================
Files 114 114
Lines 63158 63159 +1
============================================
+ Hits 44624 44649 +25
+ Misses 18534 18510 -24
|
3bb1f12
to
9884508
Compare
9884508
to
8a9d80e
Compare
Looks simple, but what's the use case? Why does a module need to update args in runtime? A module can already have config that is updated using CONFIG SET, right? |
eb9712a
to
fbc66dd
Compare
5038d52
to
ed24ce1
Compare
@zuiderkwast I update the top description for this PR, i think this is a good way to access the updated module arguments. Pls take a look when you have time, Thanks a lot |
You added a module API to access the argv. Interesting. But, I am not convinced. :) In a program written in C, the arguments are passed to main as The MODULE UNLOAD + MODULE LOAD doesn't have this problem. |
ed24ce1
to
50aa816
Compare
Thanks for your comment, but some cons for operation MODULE UNLOAD + MODULE LOAD
I would like to create an issue to let community to discuss this problem. Thanks |
50aa816
to
e313f86
Compare
0caa3bd
to
69c5083
Compare
69c5083
to
b4d698d
Compare
@madolson As we discussed, I desgin the API as int VM_UpdateRuntimeArgs(ValkeyModuleCtx *ctx, int argc, ValkeyModuleString **argv), please take a look, Thanks |
b4d698d
to
c35a618
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Only documentation comment missing.
What about VM_GetRuntimeArgs, is it not needed?
src/module.c
Outdated
@@ -3042,6 +3042,23 @@ client *moduleGetReplyClient(ValkeyModuleCtx *ctx) { | |||
} | |||
} | |||
|
|||
int VM_UpdateRuntimeArgs(ValkeyModuleCtx *ctx, int argc, ValkeyModuleString **argv) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment. It is used for generated documentation. Without a comment, the function will not be included in the API documentation. The comment needs to use correct markdown syntax.
You can try the ruby script to generate the documentation markdown: utils/generate-module-api-doc.rb
. (Later, we run the script and save the output in the valkey-doc repo in the file topics/module-api-ref.md
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed, add comments already
fbc6ca1
to
67e9459
Compare
src/module.c
Outdated
/* ValkeyModule_UpdateRuntimeArgs can be used to update the values of module->loadmod | ||
* so that the updated values can be saved into conf file once 'config rewrite' command | ||
* is called | ||
* One example can be found in file modules/moduleparameter.c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good, but I have some small comments:
module->loadmod
is something internal in Valkey. Module authors are not aware of this. Let's assume module authors are know about the API documentation and valkeymodule.h
.
Usually we write commands in uppercase, like CONFIG REWRITE.
Dot is missing after "is called".
Is the example in src/modules/ or tests/modules/ ? We have both, so it's better to be specific. Also it can be good mention that that it is in the Valkey source code, because the documentation is published in other places and module authors are maybe not even looking at valkey source code.
2d51ed9
to
e260229
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for many small reviews. I was going to click Approve, but then I read the test case. more carefully and found some strange function and command names. :)
tests/modules/moduleparameter.c
Outdated
if (ValkeyModule_Init(ctx,"myhello",1,VALKEYMODULE_APIVER_1) | ||
== VALKEYMODULE_ERR) return VALKEYMODULE_ERR; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"myhello"?
Maybe "moduleparameter" is more descriptive?
tests/modules/moduleparameter.c
Outdated
if (ValkeyModule_CreateCommand(ctx,"hello.hi", | ||
GET_HELLO,"fast",0,0,0) == VALKEYMODULE_ERR) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Command name "hello.hi" and function name GET_HELLO are not perfect names. :)
Something like "updateargs", updateArgsCommand?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your comments, it is updated
ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc); | ||
return ValkeyModule_ReplyWithSimpleString(ctx, "Module runtime args test"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc); | |
return ValkeyModule_ReplyWithSimpleString(ctx, "Module runtime args test"); | |
ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc); | |
return ValkeyModule_ReplyWithSimpleString(ctx, "Module runtime args test"); |
I guess we should probably apply the formatter on these files as well.
src/module.c
Outdated
* The function parameter 'argc' indicates the number of updated arguments, and 'argv' | ||
* represents the values of the updated arguments. | ||
* Once 'CONFIG REWRITE' command is called, the updated argument values can be saved into conf file. | ||
* One example can be found in file tests/modules/moduleparameter.c. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't normally reference the test modules since these are rendered here: https://valkey.io/topics/modules-api-ref/, which doesn't clearly map to the test files anymore. I'm not sure it's really needed to show an example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like no specific test file is mentioned in reference, I will remove it.
if (!ctx->module->onload) { | ||
return VALKEYMODULE_ERR; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this only allowed at startup? I thought the whole point was they were able to update these at any point in time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'm surprised the test case passes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition "!ctx->module->onload" is checked here is not like what you thought it can be only allowed to update at startup, the goal is to check if ctx->module->onload is NULL to prevent NULL pointer exception. This API can be called at any time during runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it means that onload is ongoing. If it doesn't, then there is something wrong.
I tried to follow the function calls that happen when a module is loaded. This is what I could find:
- MODULE LOAD -> moduleCommand -> moduleLoad.
- moduleLoad loads the module file using dlopen.
- moduleLoad finds the ValkeyModule_OnLoad function in the module using dlsym.
- moduleLoad calls the ValkeyModule_OnLoad in the module.
- The module's ValkeyModule_OnLoad function calls ValkeyModule_Init.
- ValkeyModule_Init (implemented in valkeymodule.h) calls ValkeyModule_SetModuleAttribs.
- VM_SetModuleAttribs creates the struct ctx->module and sets ctx->module->onload = 1.
- The ValkeyModule_OnLoad function calls other functions, such as ValkeyModule_CreateCommand
- The ValkeyModule_OnLoad function returns.
- moduleLoad logs serverLog(LL_NOTICE, "Module '%s' loaded from %s", ctx.module->name, path);
- moduleLoad sets ctx.module->onload = 0;
- This ctx is freed, but the module object is added to a dict.
There is no other place that onload is set. That means onload = 1 only when ValkeyModule_OnLoad is running.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The onload field in ValkeyModule is not a pointer. It is an int.
int onload; /* Flag to identify if the call is being made from Onload (0 or 1) */
src/redismodule.h
Outdated
@@ -357,6 +357,7 @@ | |||
#define RedisModule_SetModuleAttribs ValkeyModule_SetModuleAttribs | |||
#define RedisModule_IsModuleNameBusy ValkeyModule_IsModuleNameBusy | |||
#define RedisModule_WrongArity ValkeyModule_WrongArity | |||
#define RedisModule_UpdateRuntimeArgs ValkeyModule_UpdateRuntimeArgs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Redis module API is just for backward compatibilty. We don't add functions to that API.
#define RedisModule_UpdateRuntimeArgs ValkeyModule_UpdateRuntimeArgs |
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
Signed-off-by: hwware <wen.hui.ware@gmail.com>
d62c9cd
to
a117ce9
Compare
|
||
int test_module_update_parameter(ValkeyModuleCtx *ctx, | ||
ValkeyModuleString **argv, int argc) { | ||
ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check that ValkeyModule_UpdateRuntimeArgs returns VALKEYMODULE_OK here.
assert_not_equal [lsearch $modulename moduleparameter] -1 | ||
string match "10 20 30" [lmap x [r module list] {dict get $x args}] | ||
r testmoduleparameter.update.parameter 40 50 60 70 | ||
string match "40 50 60 70" [lmap x [r module list] {dict get $x args}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not an assert. It will silently fail. It just returns 0 and the return value is ignored here.
Before Redis OSS 7, if we load a module with some arguments during runtime,
and run the command "config rewrite", the module information will not be saved into the
config file.
Since Redis OSS 7 and Valkey 7.2, if we load a module with some arguments during runtime,
the module information (path, arguments number, and arguments value) can be saved into the config file after config rewrite command is called.
Thus, the module will be loaded automatically when the server startup next time.
Following is one example:
bind 172.25.0.58
port 7000
protected-mode no
enable-module-command yes
Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
dir "/home/ubuntu/valkey"
save 3600 1 300 100 60 10000
user default on nopass sanitize-payload ~* &* +https://github.com/ALL
loadmodule tests/modules/datatype.so 10 20
However, there is one problem.
If developers write a module, and update the running arguments by someway, the updated arguments can not be saved into the config file even "config rewrite" is called.
The reason comes from the following function
rewriteConfigLoadmoduleOption (src/config.c)
void rewriteConfigLoadmoduleOption(struct rewriteConfigState *state) {
..........
struct ValkeyModule *module = dictGetVal(de);
line = sdsnew("loadmodule ");
line = sdscatsds(line, module->loadmod->path);
for (int i = 0; i < module->loadmod->argc; i++) {
line = sdscatlen(line, " ", 1);
line = sdscatsds(line, module->loadmod->argv[i]->ptr);
}
rewriteConfigRewriteLine(state, "loadmodule", line, 1);
.......
}
The function only save the initial arguments information (module->loadmod) into the configfile.
After core members discuss, ref #1177
We decide add the following API to implement this feature:
Original proposal:
int VM_UpdateRunTimeArgs(ValkeyModuleCtx *ctx, int index, char *value);
Updated proposal:
ValkeyModuleString **values VM_GetRuntimeArgs(ValkeyModuleCtx *ctx);
**int VM_UpdateRuntimeArgs(ValkeyModuleCtx *ctx, int argc, ValkeyModuleString **values);
Why we do not recommend the following way:
MODULE UNLOAD
Update module args in the conf file
MODULE LOAD
I think there are the following disadvantages: