Skip to content

Conversation

@rjd15372
Copy link
Member

@rjd15372 rjd15372 commented Nov 20, 2025

This PR restructures the Lua scripting functionality by extracting
it from the core Valkey server into a separate Valkey module. This change
enables the possibility of a backwards compatible Lua engine upgrade, as well
as, the flexibility in building Valkey without the Lua engine.

Important: from a user's point of view, there's no difference in using
the EVAL of FUNCTION/FCALL scripts. This PR is fully backward compatible
with respect to the public API.

The main code change is the move and adaptation of the Lua engine source
files from src/lua to src/modules/lua. The original Lua engine code is
adapted to use the module API to compile and execute scripts.

The main difference between the original code and the new, is the
serialization and deserialization of Valkey RESP values into, and from,
Lua values. While in the original implementation the parsing of RESP values
was done directly from the client buffer, in the new implementation the
parsing is done from the ValkeyModuleCallReply object and respective API.

The Makefile and CMake build systems were also updated to build and
integrate the new Lua engine module, within the Valkey server build
workflow.
When the Valkey server is built, the Lua engine module is also built,
and, the Lua module is loaded automatically by the server upon startup.
When running make install the Lua engine module is installed in the
default system library directory.
There's a new build option, called BUILD_LUA, that if set to no allows to
build Valkey server without building the Lua engine.

This modular architecture enables future development of additional Lua
engine modules with newer Lua versions that can be loaded alongside the
current engine, facilitating gradual migration paths for users.

@rjd15372 rjd15372 self-assigned this Nov 20, 2025
@rjd15372 rjd15372 added the enhancement New feature or request label Nov 20, 2025
@rjd15372
Copy link
Member Author

This PR is rebased on top of #2836 . When #2836 is merged, I'll update this PR.

This commit restructures the Lua scripting functionality by extracting
it from the core Valkey server into a separate Valkey module. This change
enables the possibility of a backwards compatible Lua engine upgrade, as well
as, the flexibility in building Valkey without the Lua engine.

**Important**: from a user's point of view, there's no difference in using
the `EVAL` of `FUNCTION/FCALL` scripts. This PR is fully backward compatible
with respect to the public API.

The main code change is the move and adaptation of the Lua engine source
files from `src/lua` to `src/modules/lua`. The original Lua engine code is
adapted to use the module API to compile and execute scripts.

The main difference between the original code and the new, is the
serialization and deserialization of Valkey RESP values into, and from,
Lua values. While in the original implementation the parsing of RESP values
was done directly from the client buffer, in the new implementation the
parsing is done from the `ValkeyModuleCallReply` object and respective API.

The Makefile and CMake build systems were also updated to build and
integrate the new Lua engine module, within the Valkey server build
workflow.
When the Valkey server is built, the Lua engine module is also built,
and, the Lua module is loaded automatically by the server upon startup.
When running `make install` the Lua engine module is installed in the
default system library directory.
There's a new build option, called `WITHOUT_LUA`, that if set allows to
build Valkey server without building the Lua engine.

This modular architecture enables future development of additional Lua
engine modules with newer Lua versions that can be loaded alongside the
current engine, facilitating gradual migration paths for users.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
@zuiderkwast
Copy link
Contributor

Wow!

Some initial comments:

  • For the build option, why not use the name BUILD_LUA (default yes), to align with the build options BUILD_TLS and BUILD_RDMA?
  • For backward compatibility, the lua module needs to load by default. To disable this auto-loading, we need a new config, don't we? I can't see it mentioned here.
  • Can the lua module be unloaded using MODULE UNLOAD?

@rjd15372
Copy link
Member Author

  • For the build option, why not use the name BUILD_LUA (default yes), to align with the build options BUILD_TLS and BUILD_RDMA?

Sure, that makes more sense. I'll update the PR.

  • For backward compatibility, the lua module needs to load by default. To disable this auto-loading, we need a new config, don't we? I can't see it mentioned here.

I was thinking that if the lua module is built then it would always be loaded by default. But we can add a new config to disable auto-loading even if the lua module is built.

  • Can the lua module be unloaded using MODULE UNLOAD?

Yes

@zuiderkwast
Copy link
Contributor

zuiderkwast commented Nov 20, 2025

I was thinking that if the lua module is built then it would always be loaded by default. But we can add a new config to disable auto-loading even if the lua module is built.

Yeah, we can discuss it with the core team.

I believe in many contexts, such as in pre-built containers, the module is already built. Many users don't build their own binaries.

@rjd15372
Copy link
Member Author

I think it makes sense to have that config option to disable auto-load.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
@rjd15372
Copy link
Member Author

I think it makes sense to have that config option to disable auto-load.

@zuiderkwast I vote for implementing such option in a follow up PR. This PR is already huge to review.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
@codecov
Copy link

codecov bot commented Nov 21, 2025

Codecov Report

❌ Patch coverage is 92.59259% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.98%. Comparing base (05540af) to head (f36121f).
⚠️ Report is 1 commits behind head on unstable.

Files with missing lines Patch % Lines
src/server.c 83.33% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #2858      +/-   ##
============================================
+ Coverage     72.41%   73.98%   +1.57%     
============================================
  Files           128      124       -4     
  Lines         70414    68643    -1771     
============================================
- Hits          50987    50784     -203     
+ Misses        19427    17859    -1568     
Files with missing lines Coverage Δ
src/config.c 80.75% <100.00%> (+2.31%) ⬆️
src/eval.c 87.46% <100.00%> (ø)
src/module.c 26.57% <100.00%> (+16.79%) ⬆️
src/replication.c 86.04% <ø> (+0.10%) ⬆️
src/script.c 89.03% <ø> (+8.89%) ⬆️
src/scripting_engine.c 56.88% <100.00%> (+3.51%) ⬆️
src/server.c 88.65% <83.33%> (+0.19%) ⬆️

... and 26 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Signed-off-by: Ricardo Dias <ricardo.dias@percona.com>
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.

Just some initial comments. I'll do another pass later. The change is not as huge as the +/- numbers indicate. Many lines are moved to other files.

The build options should be mentioned in the README.md.

@@ -0,0 +1,542 @@
#include "../../valkeymodule.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

We should add this copyright header to new files:

Suggested change
#include "../../valkeymodule.h"
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "../../valkeymodule.h"

@@ -0,0 +1,72 @@
#include "list.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#include "list.h"
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "list.h"

} ListIter;

List *list_create(void) {
List *list = ValkeyModule_Calloc(1, sizeof(List));
Copy link
Contributor

Choose a reason for hiding this comment

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

Not that it matters much, but calloc doesn't seem to be needed. We could use ValkeyModule_Alloc.

Suggested change
List *list = ValkeyModule_Calloc(1, sizeof(List));
List *list = ValkeyModule_Alloc(sizeof(List));

if (b) {
ValkeyModule_ReplyWithLongLong(ctx, 1);
} else {
ValkeyModule_ReplyWithCString(ctx, NULL);
Copy link
Contributor

@zuiderkwast zuiderkwast Nov 20, 2025

Choose a reason for hiding this comment

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

This logic is weird. The change is preserving the logic though. It looks correct.

I believe this is equivalent though:

Suggested change
ValkeyModule_ReplyWithCString(ctx, NULL);
ValkeyModule_ReplyWithNull(ctx);

Comment on lines +303 to +305
error_code = lm_strcpy("ERR");
final_msg = lm_asprintf("%s %s", error_code, msg);
ValkeyModule_Free(error_code);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why allocate a temporary "ERR" string? Can't we simply:

Suggested change
error_code = lm_strcpy("ERR");
final_msg = lm_asprintf("%s %s", error_code, msg);
ValkeyModule_Free(error_code);
final_msg = lm_asprintf("ERR %s", msg);

char *lm_strcpy(const char *str) {
size_t len = strlen(str);
char *res = ValkeyModule_Alloc(len + 1);
strncpy(res, str, len + 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

We already did strlen above so no need to search for the \0 again. We can use memcpy.

Suggested change
strncpy(res, str, len + 1);
memcpy(res, str, len + 1);

Comment on lines +310 to +312
error_code = lm_strcpy(err_buffer + 1);
final_msg = lm_asprintf("%s %s", error_code, msg);
ValkeyModule_Free(error_code);
Copy link
Contributor

Choose a reason for hiding this comment

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

We can avoid a temp allocation.

Suggested change
error_code = lm_strcpy(err_buffer + 1);
final_msg = lm_asprintf("%s %s", error_code, msg);
ValkeyModule_Free(error_code);
final_msg = lm_asprintf("%s %s", err_buffer + 1, msg);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants