Skip to content

Conversation

@rjd15372
Copy link
Member

@rjd15372 rjd15372 commented Jan 28, 2026

This commit adds a new module API function called
ValkeyModule_CallArgv to allow modules to call server commands. This function is a low-latency version of ValkeyModule_Call, which can be used in latency sensitive modules like the Lua module.

The signature of the new function is the following:

ValkeyModuleCallRawReply *ValkeyModule_CallArgv(ValkeyModuleContext ctx, ValkeyModuleString **argv, int argc, int flags, ValkeyModuleString **error);

This new function differs from the already existing ValkeyModule_Call in the following items:

  • VM_CallArgv already receives the arguments array argv that can be passed directly to the client object, avoiding the parsing of the format string of (VM_Call), and also the allocation of a new argv array. The caller of VM_CallArgv has the owership of argv and is responsible for its lifetime.
  • Command call flags are also passed directly in VM_CallArgv, which avoids the flag parsing done in `VM_Call.
  • The reply of a command is represented by the ValkeyModuleCallRawReply object, which in fact is just an alias for the fake client that executed the command. This object allows the VM_CallArgv caller to access the command result encoded in RESP without any memory allocation most of the times.

There are four additional API functions to work with the ValkeyModuleCallRawReply object.

ValkeyModuleCallReply *ValkeyModule_CallRawReplyToCallReply(ValkeyModuleCtx *ctx, ValkeyModuleCallRawReply *raw_reply);

int ValkeyModule_CallRawReplyIsBlocked(ValkeyModuleCallRawReply *raw_reply);

char *ValkeyModule_CallRawReplyBuffer(ValkeyModuleCallRawReply *raw_reply, int *is_owner);

void ValkeyModule_CallRawReplyRelease(ValkeyModuleCallRawReply *raw_reply);

The VM_CallRawReplyToCallReply function, converts a raw reply object into a reply object. When using this function, the raw_reply object cannot be used anymore, and there is no need to call VM_CallRawReplyRelease on it.

The VM_CallRawReplyIsBlocked checks whether the raw_reply corresponds to a blocking client reply. When this function returns true, then the user should convert the raw reply in a ValkeyModuleCallReply object, which will correspond to a promise reply.

The VM_CallRawReplyBuffer will return a C string buffer with the RESP result of the command. In most cases, this buffer points directly to the client reply buffer, and in this case the is_owner is set to 0. Otherwise, the caller becomes the owner of the buffer and is responsible for freeing it.

The VM_CallRawReplyRelease releases all resources associated with the raw reply object. This is when the faked client that performed the call returns to the fake client cache.

@rjd15372 rjd15372 requested a review from zuiderkwast January 28, 2026 16:28
@rjd15372 rjd15372 self-assigned this Jan 28, 2026
This commit adds a new module API function called
`ValkeyModule_CallArgv` to allow modules to call server commands.
This function is a low-latency version of `ValkeyModule_Call`, which can
be used in latency sensitive modules like the Lua module.

The signature of the new function is the following:

```c
ValkeyModuleCallRawReply *ValkeyModule_CallArgv(ValkeyModuleContext ctx, ValkeyModuleString **argv, int argc, int flags, ValkeyModuleString **error);
```

This new function differs from the already existing `ValkeyModule_Call`
in the following items:

* `VM_CallArgv` already receives the arguments array `argv` that can be
   passed directly to the client object, avoiding the parsing of the
   format string of (VM_Call), and also the allocation of a new `argv`
   array. The caller of `VM_CallArgv` has the owership of `argv` and is
   responsible for its lifetime.
* Command call `flags` are also passed directly in `VM_CallArgv`, which
  avoids the flag parsing done in `VM_Call.
* The reply of a command is represented by the
  `ValkeyModuleCallRawReply` object, which in fact is just an alias for
  the fake client that executed the command. This object allows the
  `VM_CallArgv` caller to access the command result encoded in RESP
  without any memory allocation most of the times.

There are four additional API functions to work with the
`ValkeyModuleCallRawReply` object.

```c
ValkeyModuleCallReply *ValkeyModule_CallRawReplyToCallReply(ValkeyModuleCtx *ctx, ValkeyModuleCallRawReply *raw_reply);

int ValkeyModule_CallRawReplyIsBlocked(ValkeyModuleCallRawReply *raw_reply);

char *ValkeyModule_CallRawReplyBuffer(ValkeyModuleCallRawReply *raw_reply);

void ValkeyModule_CallRawReplyRelease(ValkeyModuleCallRawReply *raw_reply);
```

The `VM_CallRawReplyToCallReply` function, converts a raw reply object into
a reply object. When using this function, the `raw_reply` object cannot be
used anymore, and there is no need to call `VM_CallRawReplyRelease` on
it.

The `VM_CallRawReplyIsBlocked` checks whether the `raw_reply`
corresponds to a blocking client reply. When this function returns
`true`, then the user should convert the raw reply in a
`ValkeyModuleCallReply` object, which will correspond to a promise
reply.

The `VM_CallRawReplyBuffer` will return a C string buffer with the RESP
result of the command. In most cases, this buffer points directly to the
client reply buffer, and in this case the `is_owner` is set to `0`.
Otherwise, the caller becomes the owner of the buffer and is responsible
for freeing it.

The `VM_CallRawReplyRelease` releases all resources associated with the
raw reply object. This is when the faked client that performed the call
returns to the fake client cache.

Signed-off-by: Ricardo Dias <[email protected]>
@codecov
Copy link

codecov bot commented Jan 28, 2026

Codecov Report

❌ Patch coverage is 43.97163% with 79 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.75%. Comparing base (9735bac) to head (9cf0cd3).
⚠️ Report is 26 commits behind head on unstable.

Files with missing lines Patch % Lines
src/module.c 43.97% 79 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #3122      +/-   ##
============================================
+ Coverage     74.34%   74.75%   +0.40%     
============================================
  Files           129      129              
  Lines         71011    71274     +263     
============================================
+ Hits          52792    53279     +487     
+ Misses        18219    17995     -224     
Files with missing lines Coverage Δ
src/module.c 26.38% <43.97%> (-0.13%) ⬇️

... and 34 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.

@zuiderkwast zuiderkwast added the major-decision-pending Major decision pending by TSC team label Jan 28, 2026
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 performance

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants