Skip to content

feat(redis): add Redis backend with async transfers and nixlbench support#1791

Open
gaowayne wants to merge 24 commits into
ai-dynamo:mainfrom
hxieustc:pr_nixl_kv_plugin_interface_redis
Open

feat(redis): add Redis backend with async transfers and nixlbench support#1791
gaowayne wants to merge 24 commits into
ai-dynamo:mainfrom
hxieustc:pr_nixl_kv_plugin_interface_redis

Conversation

@gaowayne

@gaowayne gaowayne commented Jun 17, 2026

Copy link
Copy Markdown
## What?

This PR adds a production `REDIS` storage backend to NIXL, together with build, test, documentation, and nixlbench integration.

The implementation is Redis-specific and follows the direct backend structure used by plugins such as INFINIA:

```text
nixlBackendEngine
└── nixlRedisKVEngine
    └── iRedisClient
        └── hiredisAsyncClient

There is intentionally no generic KV backend layer or installed KV plugin API.

Redis backend

  • Registers the dynamic or static plugin as backend name REDIS.
  • Supports DRAM_SEG and OBJ_SEG.
  • Implements asynchronous NIXL_WRITE and NIXL_READ using Redis SET and GET.
  • Implements synchronous queryMem() using Redis EXISTS.
  • Uses a dedicated hiredis/libevent async connection for transfers.
  • Uses a separate blocking hiredis connection for synchronous existence checks.
  • Maps descriptor metaInfo to the Redis key, falling back to the decimal devId.
  • Resolves all transfer keys before dispatching commands, preventing partially submitted transfers.
  • Exposes asynchronous completion through the normal NIXL postXfer() / checkXfer() request-handle lifecycle.

The internal iRedisClient interface isolates hiredis/libevent and provides a deterministic unit-test seam. It is not intended as a generic KV extension API.

Configuration

Connection settings are resolved once into an internal RedisConfig and passed to hiredisAsyncClient.

Configuration precedence is:

  1. Valid NIXL backend parameters
  2. Corresponding REDIS_* environment variables
  3. Built-in defaults
Backend parameter Environment fallback Default
host REDIS_HOST localhost
port REDIS_PORT 6379
username REDIS_USERNAME empty
password REDIS_PASSWORD empty
db none 0

Authentication behavior:

  • Empty password: do not send AUTH; intended for Redis deployments that permit unauthenticated access.
  • Password only: send AUTH password for the default/legacy user.
  • Username and password: send ACL-style AUTH username password.
  • Username without password: reject backend creation.

Explicit empty username or password parameters override environment fallbacks.

nixlbench integration

  • Adds REDIS as a nixlbench storage backend.
  • Uses Redis keys carried in descriptor metadata.
  • Seeds Redis keys before READ benchmarks.
  • Adds Redis dependency handling to the nixlbench build.
  • Adds --redis-only container build support for a static REDIS-focused image.

Build integration

  • Supports dynamic [libplugin_REDIS.so](http://libplugin_redis.so/) builds.
  • Supports static REDIS plugin registration.
  • Requires hiredis, libevent, and libevent-pthreads.
  • Skips the plugin with a warning when dependencies are unavailable during a default all-plugin build.
  • Fails configuration when REDIS is explicitly requested but its dependencies are unavailable.
  • Does not require a Redis-specific ASIO executor or thread pool.

Why?

Redis is widely deployed as a low-latency byte-oriented store and naturally fits NIXL’s storage descriptor model.

This backend enables applications and benchmarks to access Redis through the normal NIXL registration and transfer APIs without introducing a speculative generic KV framework. The direct nixlBackendEngine implementation keeps the plugin consistent with established NIXL backend architecture while retaining a small client boundary for hiredis isolation and testing.

Transfer flow

WRITE / READ

nixlAgent
  → nixlRedisKVEngine::prepXfer()
      validates operation, descriptor counts, and memory types
  → nixlRedisKVEngine::postXfer()
      resolves every Redis key
      creates promise/future state
      issues async SET or GET commands
      returns NIXL_IN_PROG
  → nixlRedisKVEngine::checkXfer()
      polls completion futures
      returns NIXL_IN_PROG, NIXL_SUCCESS, or backend error

queryMem

nixlAgent
  → nixlRedisKVEngine::queryMem()
  → iRedisClient::checkKeyExistsSync()
  → Redis EXISTS on the blocking connection

The synchronous connection keeps queryMem() independent from the asynchronous transfer event loop.

Testing

Redis unit coverage includes:

  • Backend capabilities and supported memory types
  • Default and parameter-based RedisConfig resolution
  • Backend-parameter precedence over environment variables
  • Unauthenticated and ACL credential validation
  • Registration and key selection
  • queryMem() found, missing, and error responses
  • Transfer validation
  • Asynchronous READ/WRITE polling and failures
  • Null request handles
  • Prevention of partial command dispatch

Validation performed:

  • Dynamic REDIS/full project build
  • Static REDIS/NIXL build
  • Redis unit tests: 11 passed
  • git diff --check
  • Live nixlbench READ/WRITE smoke test requires an available Redis server

@gaowayne gaowayne requested review from a team, aranadive, brminich and ovidiusm as code owners June 17, 2026 08:18
@copy-pr-bot

copy-pr-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

👋 Hi gaowayne! Thank you for contributing to ai-dynamo/nixl.

Your PR reviewers will review your contribution then trigger the CI to test your changes.

🚀

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Redis-backed KV plugin layer, wires it into the build and plugin system, extends nixlbench for Redis-backed storage checks, and adds documentation plus unit coverage for the new Redis path.

Changes

Redis KV Plugin and Benchmark Integration

Layer / File(s) Summary
KV abstraction
src/plugins/kv/kv_backend.h, src/plugins/kv/kv_backend.cpp
Defines the KV store interface, backend engine contract, and delegating KV engine wrapper.
Redis contracts
src/plugins/kv/redis/redis_engine.h, src/plugins/kv/redis/redis_executor.h, src/plugins/kv/redis/client.h, src/plugins/kv/redis/engine_impl.h
Declares the Redis client interface, thread-pool executor, Redis engine, and Redis engine implementation headers.
hiredis client implementation
src/plugins/kv/redis/client.cpp
Implements the async and sync Redis client paths, including connection setup, callbacks, async commands, existence checks, and fallback stubs.
Redis engine implementation
src/plugins/kv/redis/engine_impl.cpp, src/plugins/kv/redis/redis_engine.cpp
Implements Redis-backed memory registration, query, transfer preparation, async transfer scheduling, request polling, and engine construction.
Plugin wiring and build
src/plugins/kv/kv_plugin.cpp, src/plugins/kv/meson.build, src/plugins/kv/redis/meson.build, src/plugins/meson.build, meson.build, src/core/meson.build, src/core/nixl_plugin_manager.cpp, benchmark/nixlbench/src/utils/meson.build
Wires the Redis plugin into Meson, static registration, exported dependency handling, and plugin entry points.
nixlbench Redis support
benchmark/nixlbench/contrib/Dockerfile, benchmark/nixlbench/contrib/build.sh, benchmark/nixlbench/src/utils/utils.h, benchmark/nixlbench/src/utils/utils.cpp, benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
Adds Redis backend constants and seeding helpers, updates worker Redis handling, and extends Docker and benchmark build configuration.
Documentation and tests
src/plugins/kv/README.md, src/plugins/kv/redis/README.md, test/gtest/unit/meson.build, test/gtest/unit/redis/meson.build, test/gtest/unit/redis/redis.cpp
Adds KV and Redis plugin documentation and Redis unit test coverage.

Sequence Diagram(s)

sequenceDiagram
  participant nixlbench as nixlbench worker
  participant nixlRedisKVEngineImpl as Redis KV engine
  participant hiredisAsyncClient as Redis client
  participant RedisServer as Redis server

  nixlbench->>nixlRedisKVEngineImpl: prepXfer()
  nixlbench->>nixlRedisKVEngineImpl: postXfer()
  nixlRedisKVEngineImpl->>hiredisAsyncClient: putKeyAsync() / getKeyAsync()
  hiredisAsyncClient->>RedisServer: SET / GET
  RedisServer-->>hiredisAsyncClient: reply
  hiredisAsyncClient-->>nixlRedisKVEngineImpl: promise result
  nixlbench->>nixlRedisKVEngineImpl: checkXfer()
  nixlbench->>nixlRedisKVEngineImpl: queryMem()
  nixlRedisKVEngineImpl->>hiredisAsyncClient: checkKeyExistsSync()
  hiredisAsyncClient->>RedisServer: EXISTS
  RedisServer-->>hiredisAsyncClient: integer reply
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I hop through keys both fast and slow,
Redis seeds and checks just so.
The bench now nibbles, plugin-bright,
With async paws and tests in sight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the new Redis backend and nixlbench support.
Description check ✅ Passed The description covers What, Why, configuration, transfer flow, and testing, and is mostly complete despite lacking an explicit How section.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmark/nixlbench/src/utils/utils.cpp`:
- Around line 1333-1342: The synchronous redisConnect call in the connection
block has no timeout mechanism and could block indefinitely if the Redis server
is unreachable or unresponsive. Replace the redisConnect function call with
redisConnectWithTimeout and provide an appropriate timeout value (in seconds and
microseconds as separate parameters) to ensure the connection attempt fails
gracefully within a reasonable time frame instead of blocking indefinitely.
- Around line 1319-1323: The port conversion using std::atoi silently returns 0
for invalid input strings, which would cause the code to attempt connecting to
port 0 instead of falling back to the default port 6379. Replace the std::atoi
call with std::stoi wrapped in a try-catch block to properly handle invalid port
strings, and ensure that if an exception is caught or the port value is invalid
(e.g., outside the valid port range 1-65535), the code either uses the default
port or logs an appropriate error message. This ensures that invalid REDIS_PORT
environment variable values are caught and handled gracefully rather than
silently defaulting to port 0.

In `@benchmark/nixlbench/src/utils/utils.h`:
- Line 97: Replace the preprocessor macro `XFERBENCH_BACKEND_REDIS` with a
`constexpr inline std::string_view` constant following the repository convention
for backend constants. Use lowercase naming as `xferbench_backend_redis` for the
new constant. Update all usages of `XFERBENCH_BACKEND_REDIS` throughout the
codebase to use the new constant, applying `.data()` or `std::string`
conversions where necessary for comparisons and string operations.

In `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp`:
- Around line 1259-1263: The assignment of redis_remote.metaInfo = iov.metaInfo
on line 1262 is redundant because redis_remote is already copy-constructed from
iov on line 1260 via the xferBenchIOV constructor, which automatically copies
all member variables including metaInfo. Remove the redundant metaInfo
assignment line to eliminate unnecessary duplication.
- Around line 1048-1049: The descriptor list creation at lines 1048-1049 uses a
two-step pattern (constructing an empty list with DRAM_SEG, then calling
iovListToNixlRegDlist) which differs from the consistent pattern used elsewhere
in the file at lines 990, 1021, and 1098. Replace the two-line pattern with the
single-line assignment pattern where nixl_reg_dlist_t desc_list is directly
assigned the result of calling iovListToNixlRegDlist with the iov_list and
appropriate segment type, ensuring consistency across all similar descriptor
list creations in the file.

In `@src/plugins/kv/kv_backend.cpp`:
- Around line 21-26: Replace the debug-only assert statement in the nixlKVEngine
constructor that validates impl_ is non-null with actual runtime validation
(such as throwing a std::invalid_argument exception or logging an error and
exiting the program). The current assert will be stripped from release builds,
allowing a null impl_ to be assigned to impl_ and then crash on the first method
call. Use a proper if-check followed by error handling to ensure the validation
persists in both debug and release builds.

In `@src/plugins/kv/kv_backend.h`:
- Around line 18-19: Replace the generic header guard macro `KV_BACKEND_H` with
a repository-scoped guard following the convention `NIXL_<PATH>_H` where PATH
represents the full repository-relative path. For the file at
src/plugins/kv/kv_backend.h, update both the `#ifndef` and `#define` directives
at lines 18-19, and ensure the corresponding closing `#endif` at line 161
references the same new guard macro name.

In `@src/plugins/kv/redis/client.cpp`:
- Around line 313-320: The Redis GET reply handling in the memcpy section marks
success even when the payload is truncated due to insufficient buffer capacity.
The current logic uses std::min to determine copy_len but sets success to true
regardless of whether copy_len is smaller than r->len, allowing truncated data
to be silently treated as successful. Fix this by only setting success to true
when the entire reply was copied without truncation, which means adding a check
to verify that copy_len equals r->len before marking the operation as
successful, and handle the case where copy_len is 0 or truncation occurred as a
failure condition.

In `@src/plugins/kv/redis/client.h`:
- Around line 27-28: The header guard KV_PLUGIN_REDIS_CLIENT_H does not follow
the repository-wide convention that uses the full repository-relative path
format with the NIXL_ prefix. Replace KV_PLUGIN_REDIS_CLIENT_H with the
full-path header guard format (NIXL_SRC_PLUGINS_KV_REDIS_CLIENT_H) in both the
opening `#ifndef` and `#define` directives at the top of the file, and update any
corresponding `#endif` closing guard to match this new convention consistently
throughout the file.

In `@src/plugins/kv/redis/engine_impl.cpp`:
- Around line 180-183: In the getSupportedMems() validation block where
NIXL_ERR_NOT_SUPPORTED is returned, the out parameter is not initialized before
the early return statement. This leaves the out parameter in an uninitialized
state when the error path is taken, potentially exposing stale data to callers.
Initialize the out parameter to a safe default value (typically a null pointer
or default-initialized value) immediately before the return
NIXL_ERR_NOT_SUPPORTED statement to ensure all code paths properly initialize
output parameters.
- Around line 298-333: The loop in the Redis engine implementation performs both
key validation and command dispatch within the same loop iteration. To avoid
partial side effects when validation fails on a later descriptor, refactor this
into two separate passes: first validate that all redis_key lookups from
devIdToRedisKey_ succeed for every descriptor in the loop, returning
NIXL_ERR_INVALID_PARAM immediately if any key is missing, and only after all
keys are validated should the second loop dispatch the putKeyAsync or
getKeyAsync commands.

In `@src/plugins/kv/redis/engine_impl.h`:
- Around line 23-24: Update the header guard to follow the repository convention
of using the full repository-relative path format prefixed with NIXL. Replace
the current guard `KV_PLUGIN_REDIS_ENGINE_IMPL_H` at lines 23-24 with the
appropriate guard name derived from the full repository-relative path of the
file (src/plugins/kv/redis/engine_impl.h). Also update the corresponding closing
endif guard at line 89 to match the new guard name convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 1a791ca5-8787-4268-b14c-a6a0d9461302

📥 Commits

Reviewing files that changed from the base of the PR and between 1f4468f and dc629dc.

📒 Files selected for processing (24)
  • benchmark/nixlbench/contrib/Dockerfile
  • benchmark/nixlbench/contrib/build.sh
  • benchmark/nixlbench/src/utils/meson.build
  • benchmark/nixlbench/src/utils/utils.cpp
  • benchmark/nixlbench/src/utils/utils.h
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
  • meson.build
  • src/core/meson.build
  • src/core/nixl_plugin_manager.cpp
  • src/plugins/kv/README.md
  • src/plugins/kv/kv_backend.cpp
  • src/plugins/kv/kv_backend.h
  • src/plugins/kv/kv_plugin.cpp
  • src/plugins/kv/meson.build
  • src/plugins/kv/redis/README.md
  • src/plugins/kv/redis/client.cpp
  • src/plugins/kv/redis/client.h
  • src/plugins/kv/redis/engine_impl.cpp
  • src/plugins/kv/redis/engine_impl.h
  • src/plugins/kv/redis/meson.build
  • src/plugins/kv/redis/redis_engine.cpp
  • src/plugins/kv/redis/redis_engine.h
  • src/plugins/kv/redis/redis_executor.h
  • src/plugins/meson.build

Comment thread benchmark/nixlbench/src/utils/utils.cpp Outdated
Comment thread benchmark/nixlbench/src/utils/utils.cpp Outdated
#define XFERBENCH_BACKEND_MOONCAKE "Mooncake"
#define XFERBENCH_BACKEND_HF3FS "HF3FS"
#define XFERBENCH_BACKEND_OBJ "OBJ"
#define XFERBENCH_BACKEND_REDIS "REDIS"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Prefer constexpr inline std::string_view over macro for new backend constant.

Per repository conventions, new runtime/backend string constants should use constexpr inline std::string_view with lowercase naming (e.g., xferbench_backend_redis) rather than preprocessor macros. The macro style is considered legacy.

♻️ Suggested refactor
-#define XFERBENCH_BACKEND_REDIS "REDIS"
+constexpr inline std::string_view xferbench_backend_redis = "REDIS";

Note: This would require updating all usages to use .data() or std::string conversions where needed, and updating all other backend comparisons to use the new constant name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmark/nixlbench/src/utils/utils.h` at line 97, Replace the preprocessor
macro `XFERBENCH_BACKEND_REDIS` with a `constexpr inline std::string_view`
constant following the repository convention for backend constants. Use
lowercase naming as `xferbench_backend_redis` for the new constant. Update all
usages of `XFERBENCH_BACKEND_REDIS` throughout the codebase to use the new
constant, applying `.data()` or `std::string` conversions where necessary for
comparisons and string operations.

Source: Learnings

Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp Outdated
Comment thread src/plugins/kv/kv_backend.cpp Outdated
Comment thread src/plugins/redis/redis_client.cpp
Comment thread src/plugins/kv/redis/client.h Outdated
Comment thread src/plugins/kv/redis/engine_impl.cpp Outdated
Comment thread src/plugins/kv/redis/engine_impl.cpp Outdated
Comment thread src/plugins/kv/redis/engine_impl.h Outdated
@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from dc629dc to b3af297 Compare June 22, 2026 15:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
benchmark/nixlbench/contrib/Dockerfile (1)

29-53: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden apt install with --no-install-recommends.

This layer currently installs recommended packages implicitly, which unnecessarily expands image footprint and package exposure.

🔧 Suggested patch
 RUN apt-get update -y && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
     ninja-build \
     pybind11-dev \
     libclang-dev \
@@
     build-essential \
     libhiredis-dev \
     libevent-dev \
-    redis-tools
+    redis-tools && \
+    rm -rf /var/lib/apt/lists/*
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmark/nixlbench/contrib/Dockerfile` around lines 29 - 53, The apt-get
install command in the RUN statement is missing the --no-install-recommends
flag, which causes unnecessary recommended packages to be installed, increasing
the Docker image footprint and security exposure. Add the
--no-install-recommends flag to the apt-get install command that installs
packages including ninja-build, pybind11-dev, libclang-dev, and the other build
and runtime dependencies. Place this flag after the -y option and before the
package list to ensure only explicitly requested packages are installed.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp`:
- Around line 1036-1041: The current code uses `continue` when
xferBenchUtils::putRedis fails during READ mode seeding, which skips the current
device descriptor but leaves downstream code expecting a complete per-device
`remote_regs_` list indexed by device position. This creates a mismatch between
the number of devices processed and the size of the `remote_regs_` list, causing
potential out-of-bounds access. Replace the `continue` statement with a
fail-fast mechanism (such as `return` or `break`) that exits the loop
immediately when Redis seeding fails, ensuring the device descriptor count
remains consistent with the indexing expectations in downstream code.

In `@src/plugins/kv/kv_backend.h`:
- Line 79: The destructor for the nixlKVEngine class is overriding a virtual
base destructor but is not explicitly marked with the override keyword. Add the
override keyword to the virtual destructor declaration of nixlKVEngine to
explicitly indicate that it overrides a base class virtual destructor, placing
it after the destructor signature and before the semicolon.

In `@src/plugins/kv/redis/client.cpp`:
- Line 221: The Redis client source file has formatting mismatches that
clang-format can automatically correct. Run clang-format on the client.cpp file
in the Redis plugin directory to fix the formatting inconsistencies that are
causing CI failures. This will ensure the code adheres to the project's coding
style guidelines.
- Around line 162-167: The AUTH and SELECT commands in the async initialization
are issued with nullptr callbacks, causing authentication and database selection
failures to be silently ignored. Create proper callback handler functions for
these commands that validate their responses and check for errors. Modify the
redisAsyncCommand calls for both "AUTH %s" and "SELECT %d" to pass these
callback handlers instead of nullptr, and ensure the client connection state is
only marked as ready after both AUTH (if password is provided) and SELECT (if db
is non-zero) commands complete successfully.

In `@src/plugins/kv/redis/client.h`:
- Around line 1-127: The header file src/plugins/kv/redis/client.h does not
conform to the project's code formatting standards as reported by
clang-format-diff-19 in CI. Run clang-format on the entire file to automatically
reformat it according to the project's style conventions. This should resolve
any formatting issues in the hiredisAsyncClient class definition and related
code.

In `@src/plugins/kv/redis/engine_impl.cpp`:
- Around line 91-95: The if statement checking `remote_agent != local_agent` is
missing braces around its body, which violates coding guidelines requiring
braces for all control statements. Add opening and closing braces around the
NIXL_WARN logging statement that follows the if condition to comply with the
style requirements.

In `@src/plugins/kv/redis/engine_impl.h`:
- Around line 45-55: The method declarations in the RedisEngine class
(specifically getSupportedMems, registerMem, deregisterMem, and queryMem) in
engine_impl.h do not conform to the repository's clang-format formatting
standards as verified by CI. Run clang-format on the entire engine_impl.h file
to automatically reformat these declarations according to the established coding
guidelines, which will resolve the CI formatting deltas reported in the
declaration block at lines 45-55 and also at lines 74-76.

In `@src/plugins/kv/redis/meson.build`:
- Around line 105-110: The redis_backend_lib shared_library call is missing
compile_flags that are present in the static build path, causing inconsistent
compilation between static and shared plugin artifacts. Locate the compile_flags
variable used in the static REDIS build definition in the same file, then add
these flags to the cpp_args parameter in the redis_backend_lib shared_library
call to ensure both static and shared builds use the same compiler flags.

In `@src/plugins/kv/redis/redis_engine.h`:
- Around line 1-103: The redis_engine.h file has formatting drift detected by
clang-format-diff-19, which is causing CI to fail. Run clang-format on the
redis_engine.h file using the project's clang-format configuration to
automatically fix all formatting issues in the file. This should resolve the
formatting drift in the copyright headers, includes, class definitions
iRedisClient and nixlRedisKVEngine, method declarations, and overall code style
to match the project standards.

In `@src/plugins/kv/redis/redis_executor.h`:
- Around line 1-53: The header file redis_executor.h containing the
redisThreadPoolExecutor class requires code formatting updates as flagged by the
project's clang-format CI checks. Run clang-format on this file to automatically
apply the required formatting changes and align it with the project's coding
style guidelines.
- Around line 34-37: The method name WaitUntilStopped uses PascalCase but the
repository convention requires lowerCamelCase for member methods. Rename the
method from WaitUntilStopped to waitUntilStopped in the redis_executor.h file,
and then search for and update all call sites throughout the codebase where
WaitUntilStopped is invoked to use the new lowercase name waitUntilStopped
instead.

---

Outside diff comments:
In `@benchmark/nixlbench/contrib/Dockerfile`:
- Around line 29-53: The apt-get install command in the RUN statement is missing
the --no-install-recommends flag, which causes unnecessary recommended packages
to be installed, increasing the Docker image footprint and security exposure.
Add the --no-install-recommends flag to the apt-get install command that
installs packages including ninja-build, pybind11-dev, libclang-dev, and the
other build and runtime dependencies. Place this flag after the -y option and
before the package list to ensure only explicitly requested packages are
installed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 23a86fa0-b1c2-421f-a0d3-56f4eae8784a

📥 Commits

Reviewing files that changed from the base of the PR and between dc629dc and b3af297.

📒 Files selected for processing (24)
  • benchmark/nixlbench/contrib/Dockerfile
  • benchmark/nixlbench/contrib/build.sh
  • benchmark/nixlbench/src/utils/meson.build
  • benchmark/nixlbench/src/utils/utils.cpp
  • benchmark/nixlbench/src/utils/utils.h
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
  • meson.build
  • src/core/meson.build
  • src/core/nixl_plugin_manager.cpp
  • src/plugins/kv/README.md
  • src/plugins/kv/kv_backend.cpp
  • src/plugins/kv/kv_backend.h
  • src/plugins/kv/kv_plugin.cpp
  • src/plugins/kv/meson.build
  • src/plugins/kv/redis/README.md
  • src/plugins/kv/redis/client.cpp
  • src/plugins/kv/redis/client.h
  • src/plugins/kv/redis/engine_impl.cpp
  • src/plugins/kv/redis/engine_impl.h
  • src/plugins/kv/redis/meson.build
  • src/plugins/kv/redis/redis_engine.cpp
  • src/plugins/kv/redis/redis_engine.h
  • src/plugins/kv/redis/redis_executor.h
  • src/plugins/meson.build

Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
Comment thread src/plugins/kv/kv_backend.h Outdated
Comment thread src/plugins/kv/redis/client.cpp Outdated
Comment thread src/plugins/redis/redis_client.cpp
Comment thread src/plugins/kv/redis/client.h Outdated
Comment thread src/plugins/kv/redis/engine_impl.h Outdated
Comment thread src/plugins/redis/meson.build
Comment thread src/plugins/kv/redis/redis_engine.h Outdated
Comment thread src/plugins/kv/redis/redis_executor.h Outdated
Comment thread src/plugins/kv/redis/redis_executor.h Outdated
@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from b3af297 to b1b1b03 Compare June 22, 2026 19:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
benchmark/nixlbench/contrib/Dockerfile (1)

29-53: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use --no-install-recommends in the base apt install layer.

Line 30 installs many packages without --no-install-recommends, which increases image size/surface area unnecessarily.

♻️ Minimal fix
 RUN apt-get update -y && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
     ninja-build \
     pybind11-dev \
@@
-    redis-tools
+    redis-tools && \
+    rm -rf /var/lib/apt/lists/*
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmark/nixlbench/contrib/Dockerfile` around lines 29 - 53, The apt-get
install command in the RUN layer that installs packages like ninja-build,
pybind11-dev, libclang-dev, cmake, and others is missing the
--no-install-recommends flag. Add --no-install-recommends to the apt-get install
command (after the -y flag and before the package list) to prevent the
installation of recommended packages that are not strictly required, which will
reduce the Docker image size and surface area.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmark/nixlbench/contrib/Dockerfile`:
- Around line 125-126: The Dockerfile ARG declarations for NIXL_ENABLE_PLUGINS
and NIXL_STATIC_PLUGINS are hardcoded to "REDIS", which restricts plugin
building and duplicates the --redis-only flag intent from the build script.
Either change both ARG assignments to use empty strings as values (allowing
Meson to build all plugins by default) or remove the --redis-only option from
the build script if Redis-only is the intended behavior. Clarify the intent and
ensure the Dockerfile defaults and build script flags are not redundant.

In `@benchmark/nixlbench/src/utils/utils.cpp`:
- Line 67: The backend option documentation at line 67 lists GUSLI as a valid
backend option along with REDIS and AZURE_BLOB, but the actual printed backend
list at lines 683-684 omits GUSLI. To fix this inconsistency, add GUSLI to the
backend list string that is printed at lines 683-684 so that it matches the
documented options shown in the help message at line 67, ensuring users see a
complete and accurate list of available backends when viewing configuration
output.

In `@src/plugins/kv/README.md`:
- Around line 49-52: The file map entry for the `iRedisClient` interface is
incorrectly documented as being in `redis_engine.h/.cpp` when it actually
resides in `src/plugins/kv/redis/client.h`. Update the mapping entry for
`iRedisClient` on line 49 to reflect the correct file location in
`client.h/.cpp` instead of `redis_engine.h/.cpp`.

In `@src/plugins/kv/redis/client.cpp`:
- Around line 176-183: The code is calling redisAsyncFree(asyncContext_)
immediately after redisAsyncDisconnect(asyncContext_), which causes a
double-free memory error. The hiredis async API automatically frees the context
when redisAsyncDisconnect() completes its callback, so the subsequent
redisAsyncFree() call is redundant and dangerous. Remove the
redisAsyncFree(asyncContext_) call that follows
redisAsyncDisconnect(asyncContext_) in the constructor timeout path where
connected_.load() is false. Apply this same fix pattern to any other locations
in the code where this redundant call pattern exists.

In `@src/plugins/kv/redis/meson.build`:
- Around line 62-68: The REDIS plugin build silently skips with a warning for
shared builds even when explicitly requested by the user, while static builds
properly fail with an error. Modify the condition on line 62 that currently only
checks if 'REDIS' is in static_plugins to also check if REDIS is explicitly
enabled for shared builds (check the get_option or similar mechanism for REDIS
explicit enablement). When REDIS is explicitly requested in any form and the
required dependencies (hiredis_async_dep or libevent_dep) are missing, throw an
error instead of just warning and skipping. Only allow the silent skip with a
warning when REDIS was not explicitly requested by the user.

In `@src/plugins/kv/redis/README.md`:
- Line 61: The documentation on line 61 of the README.md file incorrectly
implies that the `db` parameter can be configured via environment variables, but
the actual implementation in src/plugins/kv/redis/client.cpp only reads `db`
from custom params. Reword line 61 to clarify that `db` is configured through
NIXL custom params only, while keeping the distinction that `host`, `port`, and
`password` can come from either custom params or their respective environment
variables (REDIS_HOST, REDIS_PORT, REDIS_PASSWORD).

---

Outside diff comments:
In `@benchmark/nixlbench/contrib/Dockerfile`:
- Around line 29-53: The apt-get install command in the RUN layer that installs
packages like ninja-build, pybind11-dev, libclang-dev, cmake, and others is
missing the --no-install-recommends flag. Add --no-install-recommends to the
apt-get install command (after the -y flag and before the package list) to
prevent the installation of recommended packages that are not strictly required,
which will reduce the Docker image size and surface area.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 029f983b-216b-41e8-a2b6-96d6a47a757a

📥 Commits

Reviewing files that changed from the base of the PR and between b3af297 and b1b1b03.

📒 Files selected for processing (24)
  • benchmark/nixlbench/contrib/Dockerfile
  • benchmark/nixlbench/contrib/build.sh
  • benchmark/nixlbench/src/utils/meson.build
  • benchmark/nixlbench/src/utils/utils.cpp
  • benchmark/nixlbench/src/utils/utils.h
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
  • meson.build
  • src/core/meson.build
  • src/core/nixl_plugin_manager.cpp
  • src/plugins/kv/README.md
  • src/plugins/kv/kv_backend.cpp
  • src/plugins/kv/kv_backend.h
  • src/plugins/kv/kv_plugin.cpp
  • src/plugins/kv/meson.build
  • src/plugins/kv/redis/README.md
  • src/plugins/kv/redis/client.cpp
  • src/plugins/kv/redis/client.h
  • src/plugins/kv/redis/engine_impl.cpp
  • src/plugins/kv/redis/engine_impl.h
  • src/plugins/kv/redis/meson.build
  • src/plugins/kv/redis/redis_engine.cpp
  • src/plugins/kv/redis/redis_engine.h
  • src/plugins/kv/redis/redis_executor.h
  • src/plugins/meson.build

Comment thread benchmark/nixlbench/contrib/Dockerfile Outdated
Comment thread benchmark/nixlbench/src/utils/utils.cpp
Comment thread src/plugins/kv/README.md Outdated
Comment on lines +49 to +52
redis_engine.h/.cpp iRedisClient and nixlRedisKVEngine
engine_impl.h/.cpp nixlRedisKVEngineImpl transfer logic
client.h/.cpp hiredisAsyncClient
redis_executor.h Redis-specific ASIO executor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the file map entry for iRedisClient.

Line 49 currently states iRedisClient lives in redis_engine.h/.cpp, but the interface is declared in
src/plugins/kv/redis/client.h. Please update this mapping to avoid misleading plugin authors.

Suggested doc fix
-kv/redis/
-  redis_engine.h/.cpp         iRedisClient and nixlRedisKVEngine
+kv/redis/
+  redis_engine.h/.cpp         nixlRedisKVEngine
+  client.h/.cpp               iRedisClient and hiredisAsyncClient
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
redis_engine.h/.cpp iRedisClient and nixlRedisKVEngine
engine_impl.h/.cpp nixlRedisKVEngineImpl transfer logic
client.h/.cpp hiredisAsyncClient
redis_executor.h Redis-specific ASIO executor
redis_engine.h/.cpp nixlRedisKVEngine
engine_impl.h/.cpp nixlRedisKVEngineImpl transfer logic
client.h/.cpp iRedisClient and hiredisAsyncClient
redis_executor.h Redis-specific ASIO executor
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/README.md` around lines 49 - 52, The file map entry for the
`iRedisClient` interface is incorrectly documented as being in
`redis_engine.h/.cpp` when it actually resides in
`src/plugins/kv/redis/client.h`. Update the mapping entry for `iRedisClient` on
line 49 to reflect the correct file location in `client.h/.cpp` instead of
`redis_engine.h/.cpp`.

Comment thread src/plugins/kv/redis/client.cpp Outdated
Comment thread src/plugins/redis/meson.build
Comment thread src/plugins/kv/redis/README.md Outdated
@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from b1b1b03 to 0eb91e0 Compare June 23, 2026 20:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (8)
src/plugins/kv/kv_backend.h (2)

79-79: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Mark the overriding destructor with override.

nixlKVEngine derives from nixlBackendEngine; the destructor declaration should be ~nixlKVEngine() override;.
As per path instructions, overridden virtual methods should explicitly use override.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/kv_backend.h` at line 79, The destructor declaration for the
nixlKVEngine class is missing the override keyword. Since nixlKVEngine derives
from nixlBackendEngine and overrides its virtual destructor, add the override
keyword to the destructor declaration. Modify the ~nixlKVEngine destructor to
include override after the empty parameter list to explicitly indicate it is
overriding a base class virtual method, following the codebase convention for
overridden virtual methods.

Source: Path instructions


18-19: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the repository-relative header guard macro.

KV_BACKEND_H is too generic and can collide across headers. Use
NIXL_SRC_PLUGINS_KV_KV_BACKEND_H consistently in #ifndef/#define/#endif.
As per path instructions, headers should use traditional include guards; based on learnings, this repo uses full repository-relative NIXL_<PATH>_H guards.

Also applies to: 161-161

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/kv_backend.h` around lines 18 - 19, Replace the generic header
guard macro KV_BACKEND_H with the repository-relative macro
NIXL_SRC_PLUGINS_KV_KV_BACKEND_H to prevent collisions with other headers.
Update the `#ifndef` directive at the top of the file, the corresponding `#define`
directive, and the matching `#endif` at the end of the file to use the new
fully-qualified macro name NIXL_SRC_PLUGINS_KV_KV_BACKEND_H instead of the
generic KV_BACKEND_H.

Sources: Path instructions, Learnings

src/plugins/kv/redis/redis_executor.h (1)

34-37: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Normalize method naming to lower camel case.

WaitUntilStopped breaks the file’s own naming pattern (waitUntilIdle) and the repo convention. Rename it to waitUntilStopped and update call sites.
As per path instructions, functions/methods should use lower camel case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/redis_executor.h` around lines 34 - 37, The method
`WaitUntilStopped` uses upper camel case naming which violates the repository
convention of lower camel case (as seen in the same file with `waitUntilIdle`).
Rename the method `WaitUntilStopped` to `waitUntilStopped` in its definition,
and update all call sites throughout the codebase that invoke this method to use
the new lower camel case name.

Source: Path instructions

src/plugins/kv/redis/client.h (1)

27-28: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Adopt the full repository-path header guard.

Replace KV_PLUGIN_REDIS_CLIENT_H with NIXL_SRC_PLUGINS_KV_REDIS_CLIENT_H in the opening and closing guard.
As per path instructions, use traditional include guards; based on learnings, this repo standard is full-path NIXL_<PATH>_H.

Also applies to: 127-127

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/client.h` around lines 27 - 28, The header guard macro
KV_PLUGIN_REDIS_CLIENT_H does not follow the repository's full-path naming
convention. Replace KV_PLUGIN_REDIS_CLIENT_H with
NIXL_SRC_PLUGINS_KV_REDIS_CLIENT_H in both locations: the opening `#ifndef` and
`#define` directives at the top of the file, and the closing `#endif` comment at the
bottom of the file. This ensures consistency with the repository standard of
using full-path prefixes in the format NIXL_<PATH>_H for all header guards.

Sources: Path instructions, Learnings

src/plugins/kv/redis/README.md (1)

61-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify the db configuration source.

This line currently implies db may come from env vars, but only REDIS_HOST/PORT/PASSWORD are listed. Please explicitly separate: db from NIXL params, others from params or env fallback.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/README.md` at line 61, The documentation line describing
connection settings is ambiguous about where the `db` parameter is configured.
Currently it lists `db` alongside other parameters but then only provides
environment variable names for `host`, `port`, and `password`, leaving `db`'s
source unclear. Revise this line to explicitly separate the configuration
sources: clearly state which parameters come from NIXL custom params only, and
which can fall back to environment variables. If `db` has a corresponding
environment variable like `REDIS_DB`, include it; otherwise explicitly note that
`db` only comes from NIXL params to eliminate confusion.
src/plugins/kv/redis/engine_impl.h (2)

42-76: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Resolve the clang-format drift in declaration blocks.

CI is still reporting formatting deltas in this range (return-type/signature wrapping), which will keep the format check red until fixed.
As per path instructions, keep declaration formatting consistent (including return-type line breaks), and pipeline failures explicitly flag this range.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/engine_impl.h` around lines 42 - 76, The method
declarations in the nixlRedisKVEngineImpl class (including registerMem,
deregisterMem, queryMem, prepXfer, postXfer, checkXfer, and releaseReqH) have
inconsistent clang-format formatting with respect to return-type line breaks and
signature wrapping. Apply clang-format rules consistently across all
declarations in this range to ensure uniform formatting of return types,
parameter list alignment, and line breaks. Verify that the formatting matches
the project's clang-format configuration and that CI formatting checks pass
after the changes.

Sources: Path instructions, Pipeline failures


23-24: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the repo-standard include guard macro.

KV_PLUGIN_REDIS_ENGINE_IMPL_H should be updated to
NIXL_SRC_PLUGINS_KV_REDIS_ENGINE_IMPL_H for consistency and collision safety.
As per path instructions, headers should use traditional path-derived guards; based on learnings, this repo enforces full-path NIXL_<PATH>_H.

Also applies to: 89-89

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/engine_impl.h` around lines 23 - 24, The include guard
macro KV_PLUGIN_REDIS_ENGINE_IMPL_H does not follow the repository's standard
naming convention. Replace all occurrences of this macro name with
NIXL_SRC_PLUGINS_KV_REDIS_ENGINE_IMPL_H throughout the file, including in the
`#ifndef` directive at the top, the `#define` directive on the following line, and
the corresponding `#endif` directive at the end of the file (around line 89). This
ensures consistency with the repo's full-path-derived include guard convention
for collision safety.

Sources: Path instructions, Learnings

src/plugins/kv/kv_backend.cpp (1)

21-26: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Replace debug-only assert with release-safe validation.

impl_ is only protected by assert, so release builds can construct with null and crash later on delegated calls.

Suggested fix
 `#include` "kv_backend.h"
 `#include` <cassert>
+#include <stdexcept>
@@
 nixlKVEngine::nixlKVEngine(const nixlBackendInitParams *init_params,
                            std::unique_ptr<nixlKVEngineImpl> impl)
     : nixlBackendEngine(init_params),
       impl_(std::move(impl)) {
+    if (!impl_) {
+        throw std::invalid_argument("nixlKVEngine requires a non-null nixlKVEngineImpl");
+    }
     assert(impl_ && "nixlKVEngine requires a non-null nixlKVEngineImpl");
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/kv_backend.cpp` around lines 21 - 26, The assert statement
protecting impl_ in the nixlKVEngine constructor only executes in debug builds
and is stripped in release builds, allowing null impl_ to pass through and cause
crashes on later delegated calls. Replace the assert in the nixlKVEngine
constructor with release-safe validation, such as throwing an exception if impl_
is null, to ensure the null check is enforced consistently across both debug and
release builds.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmark/nixlbench/src/utils/utils.cpp`:
- Line 827: The checkConsistency() function's storage WRITE path at line 827
does not properly handle the Redis backend before attempting to use pread() for
validation. Redis stores keys in metaInfo rather than file descriptors, which
causes the validation to fail when using --backend=REDIS with --op_type=WRITE
and --check_consistency=1. Add a Redis-specific validation branch within
checkConsistency() that handles Redis GET validation using the metaInfo keys, or
explicitly reject the Redis backend option in WRITE consistency validation mode
before reaching the pread() call.

In `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp`:
- Around line 1258-1262: In the Redis backend branch of
prepareTransferDescriptors(), the redis_remote descriptor is not applying the
block_size parameter like the file and GUSLI storage paths do. After setting
redis_remote.addr to 0 and redis_remote.metaInfo to iov.metaInfo, add a line to
set redis_remote.len to the block_size value to ensure the configured benchmark
block size is respected for Redis transfers instead of using the default iov
length.

In `@src/plugins/kv/redis/client.cpp`:
- Around line 334-387: The redisAsyncContext is not thread-safe and must only be
accessed from the event-loop thread (eventLoopThread_), but putKeyAsync and
getKeyAsync are calling redisAsyncCommand directly from caller threads without
synchronization. To fix this, you need to marshal the redisAsyncCommand calls
onto the event-loop thread instead of executing them directly. Use a mechanism
like event_base_once to schedule the command execution on the event loop, or
implement a thread-safe command queue with a wakeup mechanism. This ensures all
asyncContext_ accesses happen only within the event-loop thread that runs
event_base_dispatch.

---

Duplicate comments:
In `@src/plugins/kv/kv_backend.cpp`:
- Around line 21-26: The assert statement protecting impl_ in the nixlKVEngine
constructor only executes in debug builds and is stripped in release builds,
allowing null impl_ to pass through and cause crashes on later delegated calls.
Replace the assert in the nixlKVEngine constructor with release-safe validation,
such as throwing an exception if impl_ is null, to ensure the null check is
enforced consistently across both debug and release builds.

In `@src/plugins/kv/kv_backend.h`:
- Line 79: The destructor declaration for the nixlKVEngine class is missing the
override keyword. Since nixlKVEngine derives from nixlBackendEngine and
overrides its virtual destructor, add the override keyword to the destructor
declaration. Modify the ~nixlKVEngine destructor to include override after the
empty parameter list to explicitly indicate it is overriding a base class
virtual method, following the codebase convention for overridden virtual
methods.
- Around line 18-19: Replace the generic header guard macro KV_BACKEND_H with
the repository-relative macro NIXL_SRC_PLUGINS_KV_KV_BACKEND_H to prevent
collisions with other headers. Update the `#ifndef` directive at the top of the
file, the corresponding `#define` directive, and the matching `#endif` at the end of
the file to use the new fully-qualified macro name
NIXL_SRC_PLUGINS_KV_KV_BACKEND_H instead of the generic KV_BACKEND_H.

In `@src/plugins/kv/redis/client.h`:
- Around line 27-28: The header guard macro KV_PLUGIN_REDIS_CLIENT_H does not
follow the repository's full-path naming convention. Replace
KV_PLUGIN_REDIS_CLIENT_H with NIXL_SRC_PLUGINS_KV_REDIS_CLIENT_H in both
locations: the opening `#ifndef` and `#define` directives at the top of the file,
and the closing `#endif` comment at the bottom of the file. This ensures
consistency with the repository standard of using full-path prefixes in the
format NIXL_<PATH>_H for all header guards.

In `@src/plugins/kv/redis/engine_impl.h`:
- Around line 42-76: The method declarations in the nixlRedisKVEngineImpl class
(including registerMem, deregisterMem, queryMem, prepXfer, postXfer, checkXfer,
and releaseReqH) have inconsistent clang-format formatting with respect to
return-type line breaks and signature wrapping. Apply clang-format rules
consistently across all declarations in this range to ensure uniform formatting
of return types, parameter list alignment, and line breaks. Verify that the
formatting matches the project's clang-format configuration and that CI
formatting checks pass after the changes.
- Around line 23-24: The include guard macro KV_PLUGIN_REDIS_ENGINE_IMPL_H does
not follow the repository's standard naming convention. Replace all occurrences
of this macro name with NIXL_SRC_PLUGINS_KV_REDIS_ENGINE_IMPL_H throughout the
file, including in the `#ifndef` directive at the top, the `#define` directive on
the following line, and the corresponding `#endif` directive at the end of the
file (around line 89). This ensures consistency with the repo's
full-path-derived include guard convention for collision safety.

In `@src/plugins/kv/redis/README.md`:
- Line 61: The documentation line describing connection settings is ambiguous
about where the `db` parameter is configured. Currently it lists `db` alongside
other parameters but then only provides environment variable names for `host`,
`port`, and `password`, leaving `db`'s source unclear. Revise this line to
explicitly separate the configuration sources: clearly state which parameters
come from NIXL custom params only, and which can fall back to environment
variables. If `db` has a corresponding environment variable like `REDIS_DB`,
include it; otherwise explicitly note that `db` only comes from NIXL params to
eliminate confusion.

In `@src/plugins/kv/redis/redis_executor.h`:
- Around line 34-37: The method `WaitUntilStopped` uses upper camel case naming
which violates the repository convention of lower camel case (as seen in the
same file with `waitUntilIdle`). Rename the method `WaitUntilStopped` to
`waitUntilStopped` in its definition, and update all call sites throughout the
codebase that invoke this method to use the new lower camel case name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 1e6a6197-765e-4ba6-aab1-be92a9ec1875

📥 Commits

Reviewing files that changed from the base of the PR and between b1b1b03 and 0eb91e0.

📒 Files selected for processing (24)
  • benchmark/nixlbench/contrib/Dockerfile
  • benchmark/nixlbench/contrib/build.sh
  • benchmark/nixlbench/src/utils/meson.build
  • benchmark/nixlbench/src/utils/utils.cpp
  • benchmark/nixlbench/src/utils/utils.h
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
  • meson.build
  • src/core/meson.build
  • src/core/nixl_plugin_manager.cpp
  • src/plugins/kv/README.md
  • src/plugins/kv/kv_backend.cpp
  • src/plugins/kv/kv_backend.h
  • src/plugins/kv/kv_plugin.cpp
  • src/plugins/kv/meson.build
  • src/plugins/kv/redis/README.md
  • src/plugins/kv/redis/client.cpp
  • src/plugins/kv/redis/client.h
  • src/plugins/kv/redis/engine_impl.cpp
  • src/plugins/kv/redis/engine_impl.h
  • src/plugins/kv/redis/meson.build
  • src/plugins/kv/redis/redis_engine.cpp
  • src/plugins/kv/redis/redis_engine.h
  • src/plugins/kv/redis/redis_executor.h
  • src/plugins/meson.build

Comment thread benchmark/nixlbench/src/utils/utils.cpp
Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
Comment thread src/plugins/redis/redis_client.cpp
@nv-nmailhot nv-nmailhot requested review from a team as code owners June 24, 2026 06:28
@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from 0eb91e0 to 8b203b2 Compare June 25, 2026 23:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
benchmark/nixlbench/contrib/Dockerfile (1)

29-53: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Trim recommended packages from this apt layer.

This install step still omits --no-install-recommends, which pulls extra packages into the benchmark image for no functional benefit.

♻️ Minimal fix
 RUN apt-get update -y && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmark/nixlbench/contrib/Dockerfile` around lines 29 - 53, The apt install
step in the Dockerfile is still pulling recommended packages, which bloats the
benchmark image. Update the RUN apt-get install block to use the same
minimal-install approach by adding the no-recommends option to the package
installation command, keeping the existing package list in the nixlbench contrib
Dockerfile unchanged.

Source: Linters/SAST tools

♻️ Duplicate comments (3)
src/plugins/kv/redis/README.md (1)

61-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify the db config source.

This still reads as if db can come from the env-var fallback list. Split db out explicitly so only host/port/password are env-backed and db stays custom-params only.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/README.md` at line 61, Clarify the Redis connection
settings documentation so `db` is not implied to be sourced from environment
variables. Update the README text around the Redis constructor settings to
explicitly separate `db` as a NIXL custom param only, while keeping `host`,
`port`, and `password` as the env-backed fields (`REDIS_HOST`, `REDIS_PORT`,
`REDIS_PASSWORD`).
src/plugins/kv/redis/meson.build (2)

105-110: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep compile_flags in the shared REDIS build.

The shared path still drops the repo-wide compile_flags used by the static path, so the two artifacts can compile under different warning/feature settings.

Suggested fix
     redis_backend_lib = shared_library(
         'REDIS',
         redis_sources,
         dependencies: redis_plugin_deps,
-        cpp_args: compile_defs_redis + ['-fPIC'],
+        cpp_args: compile_defs_redis + compile_flags + ['-fPIC'],
         include_directories: [nixl_inc_dirs, utils_inc_dirs],
         install: true,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/meson.build` around lines 105 - 110, The shared REDIS
build in meson.build is missing the repo-wide compile_flags that the static path
already uses, so the two artifacts can be built with different compiler
settings. Update the shared_library definition for redis_backend_lib to include
the same compile_flags used by the static REDIS target, keeping the shared and
static builds aligned under the same warning/feature configuration.

62-68: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail when REDIS is explicitly requested but its deps are missing.

This still turns -Denable_plugins=REDIS into a warning + skip because only the static-plugin path errors. The build can therefore succeed without the backend the caller asked for.

Suggested fix
 if not hiredis_async_dep.found() or not libevent_dep.found()
-    if 'REDIS' in static_plugins
+    if is_explicit_enable
+        error('REDIS plugin requested but hiredis and libevent are required. Install libhiredis-dev and libevent-dev (or equivalent), then reconfigure.')
+    elif 'REDIS' in static_plugins
         error('REDIS static plugin requested but hiredis and libevent are required. Install libhiredis-dev and libevent-dev (or equivalent), then reconfigure.')
     endif
     warning('hiredis-async or libevent not available, skipping REDIS plugin build')
     subdir_done()
 endif
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/meson.build` around lines 62 - 68, The REDIS plugin
check in meson.build only errors for the static_plugins path, so an explicit
REDIS request can still fall through to warning() and subdir_done(). Update the
dependency gate around the REDIS build logic to fail whenever REDIS is
explicitly enabled through enable_plugins or static_plugins and either
hiredis_async_dep or libevent_dep is missing, using the existing REDIS plugin
selection symbols to detect the request before skipping the subdir.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/plugins/kv/kv_backend.h`:
- Around line 29-159: Add Doxygen-style type documentation for the public KV API
in this header: `iKVStore`, `nixlKVEngineImpl`, and `nixlKVEngine` currently
lack class-level `/** ... */` comments. Document the intended ownership and
lifecycle semantics for `put`, `get`, `registerMem`, `deregisterMem`,
`prepXfer`, `postXfer`, `checkXfer`, and `releaseReqH`, and clarify how request
handles and the `impl_` ownership are managed so the exported interfaces are
properly described.

In `@src/plugins/kv/meson.build`:
- Line 1: The SPDX copyright header in this new meson.build file should use a
single year instead of a range. Update the top-of-file copyright text in
src/plugins/kv/meson.build to match the repo convention for new build-related
files, using 2026 only and keeping the SPDX header format consistent.

In `@src/plugins/kv/redis/engine_impl.cpp`:
- Around line 177-195: `nixlRedisKVEngineImpl::registerMem` currently accepts
`OBJ_SEG` and returns success even though `isValidPrepXferParams` only allows
`DRAM_SEG` for local transfers. Update the local registration path so `OBJ_SEG`
is rejected with a failure code while keeping any remote `OBJ_SEG` support in
`getSupportedMems` intact; use the existing `registerMem`, `getSupportedMems`,
and `isValidPrepXferParams` logic to keep the registration contract consistent
with transfer validation.
- Around line 257-263: Initialize the output handle on the failure path in
`prepXfer()` by clearing `handle` before the `isValidPrepXferParams()`
validation check, so a failed validation cannot leave a stale request pointer
behind. Update the `engine_impl.cpp` `prepXfer` logic to set `handle` to
null/empty up front, then keep the existing `nixlRedisBackendReqH` allocation
and `release()` assignment only on the success path.

In `@src/plugins/kv/redis/meson.build`:
- Line 1: The copyright header in the new meson.build file should use a
single-year notice instead of a range. Update the SPDX-FileCopyrightText header
at the top of the file to use 2026 only, following the repo’s convention for new
build-related files; locate it by the SPDX copyright line in this meson.build
file.
- Line 123: The redis_backend_interface declaration is missing the
redis_plugin_deps re-export, so the static REDIS path does not inherit the
hiredis/libevent/asio dependencies. Update redis_backend_interface in the
meson.build for the redis backend to include redis_plugin_deps via the
dependencies argument alongside link_with so downstream consumers in
src/core/meson.build get the full dependency set.

---

Outside diff comments:
In `@benchmark/nixlbench/contrib/Dockerfile`:
- Around line 29-53: The apt install step in the Dockerfile is still pulling
recommended packages, which bloats the benchmark image. Update the RUN apt-get
install block to use the same minimal-install approach by adding the
no-recommends option to the package installation command, keeping the existing
package list in the nixlbench contrib Dockerfile unchanged.

---

Duplicate comments:
In `@src/plugins/kv/redis/meson.build`:
- Around line 105-110: The shared REDIS build in meson.build is missing the
repo-wide compile_flags that the static path already uses, so the two artifacts
can be built with different compiler settings. Update the shared_library
definition for redis_backend_lib to include the same compile_flags used by the
static REDIS target, keeping the shared and static builds aligned under the same
warning/feature configuration.
- Around line 62-68: The REDIS plugin check in meson.build only errors for the
static_plugins path, so an explicit REDIS request can still fall through to
warning() and subdir_done(). Update the dependency gate around the REDIS build
logic to fail whenever REDIS is explicitly enabled through enable_plugins or
static_plugins and either hiredis_async_dep or libevent_dep is missing, using
the existing REDIS plugin selection symbols to detect the request before
skipping the subdir.

In `@src/plugins/kv/redis/README.md`:
- Line 61: Clarify the Redis connection settings documentation so `db` is not
implied to be sourced from environment variables. Update the README text around
the Redis constructor settings to explicitly separate `db` as a NIXL custom
param only, while keeping `host`, `port`, and `password` as the env-backed
fields (`REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: d231e727-e41d-470b-969f-7e95fb55b800

📥 Commits

Reviewing files that changed from the base of the PR and between 0eb91e0 and 8b203b2.

📒 Files selected for processing (24)
  • benchmark/nixlbench/contrib/Dockerfile
  • benchmark/nixlbench/contrib/build.sh
  • benchmark/nixlbench/src/utils/meson.build
  • benchmark/nixlbench/src/utils/utils.cpp
  • benchmark/nixlbench/src/utils/utils.h
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
  • meson.build
  • src/core/meson.build
  • src/core/nixl_plugin_manager.cpp
  • src/plugins/kv/README.md
  • src/plugins/kv/kv_backend.cpp
  • src/plugins/kv/kv_backend.h
  • src/plugins/kv/kv_plugin.cpp
  • src/plugins/kv/meson.build
  • src/plugins/kv/redis/README.md
  • src/plugins/kv/redis/client.cpp
  • src/plugins/kv/redis/client.h
  • src/plugins/kv/redis/engine_impl.cpp
  • src/plugins/kv/redis/engine_impl.h
  • src/plugins/kv/redis/meson.build
  • src/plugins/kv/redis/redis_engine.cpp
  • src/plugins/kv/redis/redis_engine.h
  • src/plugins/kv/redis/redis_executor.h
  • src/plugins/meson.build

Comment thread src/plugins/kv/kv_backend.h Outdated
Comment thread src/plugins/kv/meson.build Outdated
@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a single-year copyright header here.

This is a new .build file, so the header should use Copyright (c) 2026 rather than a year range.

Based on learnings, new build-related files in this repo should use a single year in new files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/meson.build` at line 1, The SPDX copyright header in this new
meson.build file should use a single year instead of a range. Update the
top-of-file copyright text in src/plugins/kv/meson.build to match the repo
convention for new build-related files, using 2026 only and keeping the SPDX
header format consistent.

Source: Learnings

Comment thread src/plugins/kv/redis/engine_impl.cpp Outdated
Comment on lines +177 to +195
nixlRedisKVEngineImpl::registerMem(const nixlBlobDesc &mem,
const nixl_mem_t &nixl_mem,
nixlBackendMD *&out) {
auto supported_mems = getSupportedMems();
if (std::find(supported_mems.begin(), supported_mems.end(), nixl_mem) == supported_mems.end()) {
return NIXL_ERR_NOT_SUPPORTED;
}

std::string redis_key = mem.metaInfo.empty() ? std::to_string(mem.devId) : mem.metaInfo;

if (nixl_mem == OBJ_SEG || nixl_mem == DRAM_SEG) {
auto redis_md = std::make_unique<nixlRedisMetadata>(nixl_mem, mem.devId, redis_key);
devIdToRedisKey_[mem.devId] = redis_key;
out = redis_md.release();
} else {
out = nullptr;
}

return NIXL_SUCCESS;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject OBJ_SEG during local registration.

registerMem() returns success for OBJ_SEG, but isValidPrepXferParams() on Lines 97-107 later rejects any local descriptor whose type is not DRAM_SEG. That lets callers register metadata that this backend can never use as a local transfer source/destination. Keep advertising remote OBJ_SEG support if needed, but fail local registration for OBJ_SEG so the registration contract matches the transfer contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/engine_impl.cpp` around lines 177 - 195,
`nixlRedisKVEngineImpl::registerMem` currently accepts `OBJ_SEG` and returns
success even though `isValidPrepXferParams` only allows `DRAM_SEG` for local
transfers. Update the local registration path so `OBJ_SEG` is rejected with a
failure code while keeping any remote `OBJ_SEG` support in `getSupportedMems`
intact; use the existing `registerMem`, `getSupportedMems`, and
`isValidPrepXferParams` logic to keep the registration contract consistent with
transfer validation.

Comment thread src/plugins/kv/redis/engine_impl.cpp Outdated
Comment on lines +257 to +263
if (!isValidPrepXferParams(operation, local, remote, remote_agent, local_agent)) {
return NIXL_ERR_INVALID_PARAM;
}

auto req_h = std::make_unique<nixlRedisBackendReqH>();
handle = req_h.release();
return NIXL_SUCCESS;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Initialize handle on the prep failure path.

When validation fails here, handle is left untouched. If the caller reuses a request-handle variable across operations, a failed prepXfer() can leave a stale pointer that later reaches checkXfer() or releaseReqH(). Set handle = nullptr before the validation check.

Suggested fix
 nixl_status_t
 nixlRedisKVEngineImpl::prepXfer(const nixl_xfer_op_t &operation,
                                 const nixl_meta_dlist_t &local,
                                 const nixl_meta_dlist_t &remote,
                                 const std::string &remote_agent,
                                 const std::string &local_agent,
                                 nixlBackendReqH *&handle,
                                 const nixl_opt_b_args_t *opt_args) const {
+    handle = nullptr;
     if (!isValidPrepXferParams(operation, local, remote, remote_agent, local_agent)) {
         return NIXL_ERR_INVALID_PARAM;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!isValidPrepXferParams(operation, local, remote, remote_agent, local_agent)) {
return NIXL_ERR_INVALID_PARAM;
}
auto req_h = std::make_unique<nixlRedisBackendReqH>();
handle = req_h.release();
return NIXL_SUCCESS;
nixl_status_t
nixlRedisKVEngineImpl::prepXfer(const nixl_xfer_op_t &operation,
const nixl_meta_dlist_t &local,
const nixl_meta_dlist_t &remote,
const std::string &remote_agent,
const std::string &local_agent,
nixlBackendReqH *&handle,
const nixl_opt_b_args_t *opt_args) const {
handle = nullptr;
if (!isValidPrepXferParams(operation, local, remote, remote_agent, local_agent)) {
return NIXL_ERR_INVALID_PARAM;
}
auto req_h = std::make_unique<nixlRedisBackendReqH>();
handle = req_h.release();
return NIXL_SUCCESS;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/engine_impl.cpp` around lines 257 - 263, Initialize the
output handle on the failure path in `prepXfer()` by clearing `handle` before
the `isValidPrepXferParams()` validation check, so a failed validation cannot
leave a stale request pointer behind. Update the `engine_impl.cpp` `prepXfer`
logic to set `handle` to null/empty up front, then keep the existing
`nixlRedisBackendReqH` allocation and `release()` assignment only on the success
path.

@@ -0,0 +1,123 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a single-year copyright header here.

This is a new .build file, so the header should use Copyright (c) 2026 rather than a year range.

Based on learnings, new build-related files in this repo should use a single year in new files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/meson.build` at line 1, The copyright header in the new
meson.build file should use a single-year notice instead of a range. Update the
SPDX-FileCopyrightText header at the top of the file to use 2026 only, following
the repo’s convention for new build-related files; locate it by the SPDX
copyright line in this meson.build file.

Source: Learnings

Comment thread src/plugins/kv/redis/meson.build Outdated
@hxieustc

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@benchmark/nixlbench/src/utils/meson.build`:
- Around line 28-29: The nixlbench Meson setup currently makes hiredis mandatory
through the utils dependency list, which breaks non-Redis builds. Update the
build so Redis support is optional by gating the Redis helpers behind a Meson
option or isolating them in a Redis-only translation unit, and adjust the setup
in the meson build for the utils target so only Redis-enabled builds require
hiredis while UCX/POSIX/OBJ-only builds still configure cleanly.

In `@src/plugins/kv/kv_plugin.cpp`:
- Around line 23-25: The file-local state in kv_plugin.cpp uses static for
internal linkage, but this codebase prefers an anonymous namespace in .cpp
files. Move supported_segments (and any other file-local symbols like the
redis_plugin_t alias if needed) into an anonymous namespace so the internal
linkage is explicit and consistent with the repo style.

In `@src/plugins/kv/redis/client.cpp`:
- Around line 95-104: The getRedisDB helper currently accepts partially parsed
or negative db values because it relies on std::stoi without verifying the whole
string or enforcing a non-negative range. Update getRedisDB in the Redis client
to validate the db parameter the same way as the port parsing: parse the full
custom_params->at("db") string, reject any trailing characters or malformed
input, and only return the value when it is an integer >= 0. Keep the existing
warning/fallback behavior for invalid input.
- Around line 155-157: The Redis client initialization in client.cpp should fail
fast if libevent threading setup does not succeed. In RedisClient’s constructor
or initialization path around evthread_use_pthreads() and event_base_new(),
check the return value from evthread_use_pthreads() and throw an exception
immediately when it indicates failure instead of proceeding to create
eventBase_. This keeps later cross-thread uses like event_base_once() and
event_base_loopbreak() from running on an unprotected base.

In `@src/plugins/kv/redis/engine_impl.cpp`:
- Around line 154-165: The Redis engine constructors in nixlRedisKVEngineImpl
have an initializer-list wrapping style that does not match clang-format. Update
the constructor definitions for nixlRedisKVEngineImpl so the executor_ and
redisClient_ initializer formatting follows the repository’s formatter output,
keeping the same symbols but adjusting only whitespace/wrapping to satisfy CI
format checks.

In `@src/plugins/kv/redis/engine_impl.h`:
- Around line 88-90: The registration cache in nixlKVEngineImpl is keyed only by
devId, so multiple registerMem calls on the same device can overwrite each other
and break later queryMem or transfer lookups. Update the state in
nixlKVEngineImpl to track each registration by a unique per-registration
identity from the full descriptor instead of just devId, and adjust
registerMem/queryMem/unregister logic to use that identity consistently. Keep
the Redis key mapping aligned with the specific registered region rather than
the device alone.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: ab9462d4-7569-442f-b8a8-7d36c2a549e9

📥 Commits

Reviewing files that changed from the base of the PR and between 0eb91e0 and ace488f.

📒 Files selected for processing (27)
  • benchmark/nixlbench/contrib/Dockerfile
  • benchmark/nixlbench/contrib/build.sh
  • benchmark/nixlbench/src/utils/meson.build
  • benchmark/nixlbench/src/utils/utils.cpp
  • benchmark/nixlbench/src/utils/utils.h
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
  • meson.build
  • src/core/meson.build
  • src/core/nixl_plugin_manager.cpp
  • src/plugins/kv/README.md
  • src/plugins/kv/kv_backend.cpp
  • src/plugins/kv/kv_backend.h
  • src/plugins/kv/kv_plugin.cpp
  • src/plugins/kv/meson.build
  • src/plugins/kv/redis/README.md
  • src/plugins/kv/redis/client.cpp
  • src/plugins/kv/redis/client.h
  • src/plugins/kv/redis/engine_impl.cpp
  • src/plugins/kv/redis/engine_impl.h
  • src/plugins/kv/redis/meson.build
  • src/plugins/kv/redis/redis_engine.cpp
  • src/plugins/kv/redis/redis_engine.h
  • src/plugins/kv/redis/redis_executor.h
  • src/plugins/meson.build
  • test/gtest/unit/meson.build
  • test/gtest/unit/redis/meson.build
  • test/gtest/unit/redis/redis.cpp

Comment on lines +28 to +29
dependency('dl', required: true),
dependency('hiredis', required: true),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Don't make hiredis mandatory for every nixlbench build.

utils.cpp now pulls in hiredis unconditionally, and adding it here as required: true means even UCX/POSIX/OBJ-only benchmark builds fail at configure time when libhiredis-dev is absent. The Dockerfile/build script updates only cover the container path, so local/source builds lose the previous non-Redis build path. Please gate the Redis helpers behind a Meson option or move them into a Redis-only translation unit so non-Redis nixlbench builds still configure cleanly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@benchmark/nixlbench/src/utils/meson.build` around lines 28 - 29, The
nixlbench Meson setup currently makes hiredis mandatory through the utils
dependency list, which breaks non-Redis builds. Update the build so Redis
support is optional by gating the Redis helpers behind a Meson option or
isolating them in a Redis-only translation unit, and adjust the setup in the
meson build for the utils target so only Redis-enabled builds require hiredis
while UCX/POSIX/OBJ-only builds still configure cleanly.

Comment on lines +23 to +25
using redis_plugin_t = nixlBackendPluginCreator<nixlRedisKVEngine>;

static const nixl_mem_list_t supported_segments = {DRAM_SEG, OBJ_SEG};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an anonymous namespace for file-local state.

supported_segments is given internal linkage with static, but this repo’s C++ style requires anonymous namespaces in .cpp files for internal linkage.

Proposed fix
 using redis_plugin_t = nixlBackendPluginCreator<nixlRedisKVEngine>;
 
-static const nixl_mem_list_t supported_segments = {DRAM_SEG, OBJ_SEG};
+namespace {
+const nixl_mem_list_t supported_segments = {DRAM_SEG, OBJ_SEG};
+}  // namespace

As per path instructions, "in .cpp prefer anonymous namespaces over static for internal linkage."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
using redis_plugin_t = nixlBackendPluginCreator<nixlRedisKVEngine>;
static const nixl_mem_list_t supported_segments = {DRAM_SEG, OBJ_SEG};
using redis_plugin_t = nixlBackendPluginCreator<nixlRedisKVEngine>;
namespace {
const nixl_mem_list_t supported_segments = {DRAM_SEG, OBJ_SEG};
} // namespace
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/kv_plugin.cpp` around lines 23 - 25, The file-local state in
kv_plugin.cpp uses static for internal linkage, but this codebase prefers an
anonymous namespace in .cpp files. Move supported_segments (and any other
file-local symbols like the redis_plugin_t alias if needed) into an anonymous
namespace so the internal linkage is explicit and consistent with the repo
style.

Source: Path instructions

Comment thread src/plugins/redis/redis_client.cpp Outdated
Comment on lines +95 to +104
getRedisDB(nixl_b_params_t *custom_params) {
if (custom_params && custom_params->count("db") > 0) {
try {
return std::stoi(custom_params->at("db"));
}
catch (const std::exception &) {
NIXL_WARN << "Invalid db value, using default 0";
}
}
return 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate the db parameter the same way as the port.

Line 98 accepts values like 1foo and -1 because this std::stoi result is not fully validated. That turns config typos into selecting the wrong DB or a later SELECT -1 initialization failure. Parse the full string and require db >= 0 before accepting it.

As per path instructions, pay special attention to numeric edge cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/client.cpp` around lines 95 - 104, The getRedisDB helper
currently accepts partially parsed or negative db values because it relies on
std::stoi without verifying the whole string or enforcing a non-negative range.
Update getRedisDB in the Redis client to validate the db parameter the same way
as the port parsing: parse the full custom_params->at("db") string, reject any
trailing characters or malformed input, and only return the value when it is an
integer >= 0. Keep the existing warning/fallback behavior for invalid input.

Source: Path instructions

Comment on lines +155 to +157
evthread_use_pthreads();

eventBase_ = event_base_new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and relevant call sites.
git ls-files 'src/plugins/kv/redis/client.cpp'
rg -n --hidden -S 'evthread_use_pthreads|event_base_once|event_base_loopbreak|event_base_new|event_base_dispatch|event_base_loop|event_base_loopexit' src/plugins/kv/redis/client.cpp src -g '!**/node_modules/**'

Repository: ai-dynamo/nixl

Length of output: 2172


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and relevant call sites.
git ls-files 'src/plugins/kv/redis/client.cpp'
rg -n --hidden -S 'evthread_use_pthreads|event_base_once|event_base_loopbreak|event_base_new|event_base_dispatch|event_base_loop|event_base_loopexit' src/plugins/kv/redis/client.cpp src -g '!**/node_modules/**'

Repository: ai-dynamo/nixl

Length of output: 2172


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the constructor and the event-loop/task flow around the reported lines.
sed -n '130,220p' src/plugins/kv/redis/client.cpp
printf '\n----\n'
sed -n '240,420p' src/plugins/kv/redis/client.cpp
printf '\n----\n'
sed -n '70,100p' src/plugins/kv/redis/meson.build

Repository: ai-dynamo/nixl

Length of output: 9351


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the constructor and the event-loop/task flow around the reported lines.
sed -n '130,220p' src/plugins/kv/redis/client.cpp
printf '\n----\n'
sed -n '240,420p' src/plugins/kv/redis/client.cpp
printf '\n----\n'
sed -n '70,100p' src/plugins/kv/redis/meson.build

Repository: ai-dynamo/nixl

Length of output: 9351


🌐 Web query:

libevent evthread_use_pthreads return value event_base_once thread-safe from other threads docs

💡 Result:

The function evthread_use_pthreads returns 0 on success and -1 on failure [1][2][3]. It is used to initialize Libevent for Pthreads locking and thread ID functions, which is a necessary step for using Libevent in a multithreaded environment [1][4]. Regarding thread safety, when an event_base is initialized with locking enabled (which happens by default unless the EVENT_BASE_FLAG_NOLOCK flag is used), it is safe to access that event_base from multiple threads [5][6]. The function event_base_once is therefore thread-safe in this context [5][6]. However, note that while you can safely interact with the event_base from other threads (such as adding events), the event loop itself can only be run in a single thread at a time for any given event_base [5][4]. To achieve multi-threaded event processing, you must either use multiple event_base objects or have a single thread dispatching the loop while other threads perform tasks [4].

Citations:


🌐 Web query:

libevent evthread_use_pthreads return value event_base_once thread-safe from other threads docs

💡 Result:

The function evthread_use_pthreads returns 0 on success and -1 on failure [1][2]. Regarding thread safety and usage: 1. Thread Safety: If an event_base is configured to use locking (which is the default, provided the library was built with thread support and evthread_use_pthreads was called), it is safe to access that event_base from multiple threads [3][4]. 2. event_base_once: Because event_base_once operates on an event_base, it follows these same rules. If your event_base has locking enabled, you can safely call event_base_once from a thread other than the one running the event loop [3][4]. 3. Important Caveat: While the event_base itself can be thread-safe, the event loop (e.g., event_base_dispatch or event_base_loop) can only be run in a single thread for a given event_base [3][4]. If you require multiple threads to poll for I/O, you must use a separate event_base for each thread [3][4]. Additionally, if you initialize the event_base with the EVENT_BASE_FLAG_NOLOCK flag, it will not be thread-safe, and calling functions like event_base_once concurrently from multiple threads will be unsafe [5][4].

Citations:


Fail fast when libevent threading init fails. evthread_use_pthreads() can return -1; if that happens, the event_base is left without locking, but this client later calls event_base_once() and event_base_loopbreak() across threads. Throw here instead of continuing with a non-thread-safe base.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/client.cpp` around lines 155 - 157, The Redis client
initialization in client.cpp should fail fast if libevent threading setup does
not succeed. In RedisClient’s constructor or initialization path around
evthread_use_pthreads() and event_base_new(), check the return value from
evthread_use_pthreads() and throw an exception immediately when it indicates
failure instead of proceeding to create eventBase_. This keeps later
cross-thread uses like event_base_once() and event_base_loopbreak() from running
on an unprotected base.

Comment thread src/plugins/kv/redis/engine_impl.cpp Outdated
Comment on lines +154 to +165
nixlRedisKVEngineImpl::nixlRedisKVEngineImpl(const nixlBackendInitParams *init_params)
: executor_(std::make_shared<redisThreadPoolExecutor>(
getNumThreads(getCustomParams(init_params)))) {
redisClient_ = std::make_shared<hiredisAsyncClient>(getCustomParams(init_params), executor_);
NIXL_INFO << "Redis KV backend initialized";
}

nixlRedisKVEngineImpl::nixlRedisKVEngineImpl(const nixlBackendInitParams *init_params,
std::shared_ptr<iRedisClient> redis_client)
: executor_(std::make_shared<redisThreadPoolExecutor>(
getNumThreads(getCustomParams(init_params)))),
redisClient_(std::move(redis_client)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Run clang-format on the Redis engine constructors.

CI reports a clang-format mismatch for the executor_ constructor initializer wrapping here, so this file will keep failing the format check until it matches the repository formatter output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/engine_impl.cpp` around lines 154 - 165, The Redis
engine constructors in nixlRedisKVEngineImpl have an initializer-list wrapping
style that does not match clang-format. Update the constructor definitions for
nixlRedisKVEngineImpl so the executor_ and redisClient_ initializer formatting
follows the repository’s formatter output, keeping the same symbols but
adjusting only whitespace/wrapping to satisfy CI format checks.

Source: Pipeline failures

Comment thread src/plugins/kv/redis/engine_impl.h Outdated
Comment on lines +88 to +90
std::shared_ptr<redisThreadPoolExecutor> executor_;
std::shared_ptr<iRedisClient> redisClient_;
std::unordered_map<uint64_t, std::string> devIdToRedisKey_;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Don't key Redis registrations only by devId.

Line 90 stores registration state as devId -> Redis key, but nixlKVEngineImpl::registerMem() operates on full descriptors. Two regions registered on the same device will overwrite each other here, so later queryMem/transfer lookups can resolve the wrong Redis key. Use a per-registration identity instead of just the device id.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/kv/redis/engine_impl.h` around lines 88 - 90, The registration
cache in nixlKVEngineImpl is keyed only by devId, so multiple registerMem calls
on the same device can overwrite each other and break later queryMem or transfer
lookups. Update the state in nixlKVEngineImpl to track each registration by a
unique per-registration identity from the full descriptor instead of just devId,
and adjust registerMem/queryMem/unregister logic to use that identity
consistently. Keep the Redis key mapping aligned with the specific registered
region rather than the device alone.

@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from 7b40d51 to aca54c0 Compare July 4, 2026 02:07
@gaowayne gaowayne changed the title feat(kv): add shared KV plugin interfaces and REDIS backend with nixlbench support feat(redis): add Redis backend with async transfers and nixlbench support Jul 4, 2026
@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from 80fd34a to 6e60c0c Compare July 6, 2026 16:31
gaowayne added 2 commits July 16, 2026 06:22
Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
gaowayne and others added 22 commits July 16, 2026 06:22
Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
Introduce the REDIS KV backend under src/plugins/kv/redis/, built on the
shared nixlKVEngine/nixlKVEngineImpl layer. Transfer uses hiredis-async
(SET/GET via std::promise for postXfer/checkXfer); queryMem uses a
separate synchronous hiredis connection for EXISTS.

- Add iRedisClient, hiredisAsyncClient, and nixlRedisKVEngineImpl
- Register static/shared REDIS plugin; wire meson and plugin manager
- Extend nixlbench with REDIS backend, putRedis seeding, and --redis-only
- Update Dockerfile/build.sh for libhiredis/libevent; add plugin README

Signed-off-by: Wayne Gao <wayne.gao1@solidigm.com>
- Apply clang-format-18 to redis_backend.cpp, redis_client.cpp, and
  redis unit tests to fix ternary operator placement and line wrapping
- Bump nixlbench/contrib/build.sh copyright year to 2025-2026

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a RedisConnectionPool class that wraps N hiredisAsyncClient instances
with round-robin dispatch. Pool size defaults to 8 and is configurable via
backend param pool_size or env var REDIS_POOL_SIZE. Wires the pool into the
nixlRedisKVEngine production constructor via the existing iRedisClient
shared_ptr member. Adds 5 unit tests covering pool_size config parsing.
@hxieustc hxieustc force-pushed the pr_nixl_kv_plugin_interface_redis branch from 0d4fe12 to f59892b Compare July 16, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants