Skip to content
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

Open
wants to merge 12 commits into
base: unstable
Choose a base branch
from

Conversation

hwware
Copy link
Member

@hwware hwware commented Sep 17, 2024

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:

  1. Some modules can not be unloaded. Such as the example module datatype.so, which is tests/modules/datatype.so
  2. it is not atomic operation for MODULE UNLOAD + MODULE LOAD
  3. sometimes, if we just run the module unload, the client business could be interrupted

@hwware hwware force-pushed the update-module-parameter-runtime branch from c52d35c to c3341b1 Compare September 17, 2024 17:45
Copy link

codecov bot commented Sep 17, 2024

Codecov Report

Attention: Patch coverage is 8.33333% with 11 lines in your changes missing coverage. Please review.

Project coverage is 70.73%. Comparing base (3c32ee1) to head (fc31906).
Report is 47 commits behind head on unstable.

Files with missing lines Patch % Lines
src/module.c 8.33% 11 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #1041      +/-   ##
============================================
+ Coverage     70.65%   70.73%   +0.07%     
============================================
  Files           114      116       +2     
  Lines         63158    63312     +154     
============================================
+ Hits          44624    44781     +157     
+ Misses        18534    18531       -3     
Files with missing lines Coverage Δ
src/module.c 9.64% <8.33%> (-0.03%) ⬇️

... and 33 files with indirect coverage changes

---- 🚨 Try these New Features:

@hwware hwware force-pushed the update-module-parameter-runtime branch 2 times, most recently from 3bb1f12 to 9884508 Compare September 24, 2024 00:37
@hwware hwware force-pushed the update-module-parameter-runtime branch from 9884508 to 8a9d80e Compare September 26, 2024 00:37
@zuiderkwast
Copy link
Contributor

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?

@hwware hwware force-pushed the update-module-parameter-runtime branch 2 times, most recently from eb9712a to fbc66dd Compare October 14, 2024 00:43
@hwware hwware force-pushed the update-module-parameter-runtime branch from 5038d52 to ed24ce1 Compare October 14, 2024 13:21
@zuiderkwast zuiderkwast added the major-decision-pending Major decision pending by TSC team label Oct 14, 2024
@hwware hwware changed the title Add Module set-argument command for updating module parameter during rumtime Add Module set-argument command for updating module parameter and use them by GetRunTimeArgs during rumtime Oct 15, 2024
@hwware
Copy link
Member Author

hwware commented Oct 15, 2024

@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

@zuiderkwast
Copy link
Contributor

zuiderkwast commented Oct 15, 2024

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 int main(int argc, char **argv). It's not possible to change these args later, from outside the program, while the program is running.

The argv for MODULE LOAD is the same. If you set the arguments with MODULE SET-ARGUMENTS later, the module was still loaded with the old arguments and most modules (or new modules like valkey-bloom) will not notice the arguments have changed. But there will be a problem. In the log, it looks like the module is using the new arguments, even if it is using the old arguments.

MODULE UNLOAD + MODULE LOAD doesn't have this problem.

@hwware hwware force-pushed the update-module-parameter-runtime branch from ed24ce1 to 50aa816 Compare October 16, 2024 01:03
@hwware
Copy link
Member Author

hwware commented Oct 16, 2024

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 int main(int argc, char **argv). It's not possible to change these args later, from outside the program, while the program is running.

The argv for MODULE LOAD is the same. If you set the arguments with MODULE SET-ARGUMENTS later, the module was still loaded with the old arguments and most modules (or new modules like valkey-bloom) will not notice the arguments have changed. But there will be a problem. In the log, it looks like the module is using the new arguments, even if it is using the old arguments.

MODULE UNLOAD + MODULE LOAD doesn't have this problem.

Thanks for your comment, but some cons for operation MODULE UNLOAD + MODULE LOAD

  1. some modules maybe not unloaded. Such as the example module datatype.so, which is tests/modules/datatype.so
  2. it is not atomic operation for MODULE UNLOAD + MODULE LOAD
  3. sometimes, if we just run the module unload, the client business could be interrupted
  4. through the way MODULE UNLOAD + MODULE LOAD to update module runtime args, the management plan and data plan software need to be updated as well.

I would like to create an issue to let community to discuss this problem. Thanks

@hwware hwware force-pushed the update-module-parameter-runtime branch from 50aa816 to e313f86 Compare October 22, 2024 03:16
@hwware hwware force-pushed the update-module-parameter-runtime branch 2 times, most recently from 0caa3bd to 69c5083 Compare October 31, 2024 02:25
@hwware hwware changed the title Add Module set-argument command for updating module parameter and use them by GetRunTimeArgs during rumtime Update the module args during runtime and save the new args value into the conf file Oct 31, 2024
@hwware hwware force-pushed the update-module-parameter-runtime branch from 69c5083 to b4d698d Compare October 31, 2024 06:49
@hwware hwware changed the title Update the module args during runtime and save the new args value into the conf file Add API UpdateRuntimeArgs to allow the module arguments during runtime and save the new arguments value into the conf file Oct 31, 2024
@hwware
Copy link
Member Author

hwware commented Oct 31, 2024

@madolson As we discussed, I desgin the API as int VM_UpdateRuntimeArgs(ValkeyModuleCtx *ctx, int argc, ValkeyModuleString **argv), please take a look, Thanks

src/module.c Outdated Show resolved Hide resolved
@hwware hwware force-pushed the update-module-parameter-runtime branch from b4d698d to c35a618 Compare November 1, 2024 00:57
Copy link
Contributor

@zuiderkwast zuiderkwast left a 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 Show resolved Hide resolved
tests/unit/moduleapi/moduleconfigs.tcl Outdated Show resolved Hide resolved
@hwware hwware force-pushed the update-module-parameter-runtime branch from fbc6ca1 to 67e9459 Compare November 3, 2024 13:47
src/module.c Outdated Show resolved Hide resolved
src/module.c Outdated Show resolved Hide resolved
@hwware hwware force-pushed the update-module-parameter-runtime branch from 2d51ed9 to e260229 Compare November 5, 2024 02:36
Copy link
Contributor

@zuiderkwast zuiderkwast left a 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 Show resolved Hide resolved
tests/modules/moduleparameter.c Outdated Show resolved Hide resolved
tests/modules/moduleparameter.c Outdated Show resolved Hide resolved
src/module.c Outdated Show resolved Hide resolved
src/module.c Outdated
Comment on lines 2268 to 2269
if (!ctx->module->onload) {
return VALKEYMODULE_ERR;
}
Copy link
Member

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.

Copy link
Contributor

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.

Copy link
Member Author

@hwware hwware Nov 8, 2024

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.

Copy link
Contributor

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.

Copy link
Contributor

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) */

Copy link
Member Author

@hwware hwware Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it looks like on that time, my brain is offline. Yes, you are right, it is int, not pointer. The condition here is useless, I should remove it.

src/redismodule.h Outdated Show resolved Hide resolved
@hwware hwware force-pushed the update-module-parameter-runtime branch from d62c9cd to a117ce9 Compare November 8, 2024 09:05

int test_module_update_parameter(ValkeyModuleCtx *ctx,
ValkeyModuleString **argv, int argc) {
ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc);
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update to: return ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, or

Suggested change
ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc);
int res = ValkeyModule_UpdateRuntimeArgs(ctx, argv, argc);
assert(res == VALKEYMODULE_OK);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command still needs to send a reply to the client, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just have one statement as return ValkeyModule_ReplyWithSimpleString(ctx, "OK");

tests/unit/moduleapi/moduleconfigs.tcl Outdated Show resolved Hide resolved
@hwware hwware force-pushed the update-module-parameter-runtime branch from 357fa75 to aa2ba36 Compare November 22, 2024 19:51
set modulename [lmap x [r module list] {dict get $x name}]
assert_not_equal [lsearch $modulename moduleparameter] -1
assert_equal "{10 20 30}" [lmap x [r module list] {dict get $x args}]
r testmoduleparameter.update.parameter 40 50 60 70
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should return OK on success, right?

Suggested change
r testmoduleparameter.update.parameter 40 50 60 70
assert_equal OK [r testmoduleparameter.update.parameter 40 50 60 70]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe it returns the string "Module runtime args test", the reply sent by this command in the previous commits.

Suggested change
r testmoduleparameter.update.parameter 40 50 60 70
assert_equal "Module runtime args test" [r testmoduleparameter.update.parameter 40 50 60 70]

... but OK seems more normal I think 😁

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I update this part as assert_equal OK [r testmoduleparameter.update.parameter 40 50 60 70]

@hwware hwware force-pushed the update-module-parameter-runtime branch from 158477e to 05deaf2 Compare November 22, 2024 21:34
@hwware
Copy link
Member Author

hwware commented Nov 22, 2024

I update some logic in module.c, now it works well. @zuiderkwast

@hwware hwware force-pushed the update-module-parameter-runtime branch from 05deaf2 to fc31906 Compare November 22, 2024 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
major-decision-pending Major decision pending by TSC team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[NEW]Update the module args during runtime and save the new args value into the conf file
4 participants