Skip to content

[TE][Store] refactor: centralize environment variable handling across components - #1538

Open
stmatengss wants to merge 20 commits into
mainfrom
refactor/centralize-env-vars
Open

stmatengss wants to merge 20 commits into
mainfrom
refactor/centralize-env-vars

Conversation

@stmatengss

@stmatengss stmatengss commented Feb 11, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Centralizes all getenv() calls across mooncake-transfer-engine and mooncake-store into the Environ singleton in mooncake-common/environ.h. Eliminates scattered env var parsing, consolidates defaults, and fixes several semantic bugs discovered during migration.

Key changes:

  • Environ API extensions: Added GetRedisUsername(), GetNvlinkFabricMemEnabled() (tri-state: returns true only when MC_USE_NVLINK_IPC is explicitly "0"), and ~30 other getters covering MC_MAX_SGE, MC_MAX_WR, MC_MAX_INLINE, MC_MTU, MC_WORKERS_PER_CTX, MC_SLICE_SIZE, MC_RETRY_CNT, etc.
  • GID index fix: Default changed from 3 → -1 (auto-selection), NCCL_IB_GID_INDEX fallback now handled inside Environ instead of config.cpp
  • HIP transport fix: supportFabricMem() had inverted logic — was disabling fabric-mem when IPC was disabled. Fixed: if (hip_ipc) return false;
  • NVLink transport fix: Switched from GetUseNvlinkIpc() (bool, can't distinguish unset from "0") to GetNvlinkFabricMemEnabled() to preserve opt-in semantics
  • CXL test hardening: Initialize raw pointers to nullptr, add cxl_available_ skip guard to EvictOperation test
  • Build wiring: mooncake_common linked into standalone TE builds, Python extension builds, P2P Store builds, Rust builds, and CI Go test CGO_LDFLAGS (including -lmlx5, -lxxhash)
  • Rust link fix: Added libmooncake_common.a to mooncake-store/rust/build.rs link list to resolve undefined symbol: mooncake::Environ::Get() at Rust build time
  • config.cpp log dir check: Replaced opendir() with std::filesystem::is_directory() (from main)

Module

  • Transfer Engine (mooncake-transfer-engine)
  • Mooncake Store (mooncake-store)
  • Mooncake EP (mooncake-ep)
  • Integration (mooncake-integration)
  • P2P Store (mooncake-p2p-store)
  • Python Wheel (mooncake-wheel)
  • PyTorch Backend (mooncake-pg)
  • Mooncake RL (mooncake-rl)
  • CI/CD
  • Docs
  • Other

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation update
  • Other

How Has This Been Tested?

  • Standalone Transfer Engine build: 60/60 targets compiled successfully
  • Syntax-checked modified source files (environ.cpp, config.cpp, transfer_metadata_plugin.cpp)
  • CI build failure from missing GetRedisUsername() after main merge identified and fixed
  • CI Rust build failure (undefined symbol: mooncake::Environ::Get()) identified and fixed by adding mooncake_common to Rust link list
  • Code formatted with ./scripts/code_format.sh

Checklist

  • I have performed a self-review of my own code.
  • I have formatted my own code using ./scripts/code_format.sh before submitting.
  • I have updated the documentation.
  • I have added tests to prove my changes are effective.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @stmatengss, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant refactoring effort to centralize how environment variables are accessed throughout the Mooncake codebase. By moving all environment variable retrieval into a dedicated Environ class within mooncake-common, the change aims to enhance code consistency, simplify future modifications, and reduce the potential for errors associated with scattered getenv() calls. This consolidation impacts a wide range of components, streamlining their configuration processes.

Highlights

  • Centralized Environment Variable Handling: Refactored environment variable access across mooncake-store and mooncake-transfer-engine components to use a centralized GetEnv() function from mooncake-common/environ.h. This significantly improves code maintainability and reduces duplication by consolidating environment variable retrieval logic.
  • Expanded environ.h: Extended mooncake-common/include/environ.h with numerous new getter methods for various environment variables, providing a single, consistent interface for configuration.
  • Broad Component Migration: Migrated environment variable access in client_metric, client_service, ha_helper, master, transfer_engine, topology, and all transport implementations to utilize the new centralized Environ::Get() methods, replacing direct getenv() calls.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • mooncake-common/include/environ.h
    • Added 32 new getter methods for various environment variables (e.g., GetCustomTopoJson, GetCxlDevPath, GetHandshakePort, GetStoreClientMetric, GetTeMetric, GetUseTent, GetYltLogLevel).
    • Declared corresponding private member variables for each new environment variable.
  • mooncake-common/src/environ.cpp
    • Initialized 32 new private member variables by calling appropriate GetBool, GetInt, GetString, or GetSizeT helper functions to retrieve environment variable values.
  • mooncake-store/src/client_metric.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_STORE_CLIENT_METRIC") with Environ::Get().GetStoreClientMetric().
    • Replaced direct getenv("MC_STORE_CLIENT_METRIC_INTERVAL") with Environ::Get().GetStoreClientMetricInterval().
    • Simplified the logic for parsing metric interval, removing std::stoull and exception handling as parsing is now handled by Environ.
  • mooncake-store/src/client_service.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_MS_AUTO_DISC") with Environ::Get().GetMsAutoDisc().
    • Replaced direct getenv("MC_MS_FILTERS") with Environ::Get().GetMsFilters().
    • Adjusted string parsing logic for MC_MS_FILTERS to work with std::string returned by Environ.
  • mooncake-store/src/ha_helper.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_STORE_CLUSTER_ID") with Environ::Get().GetStoreClusterId().
  • mooncake-store/src/master.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_RPC_PROTOCOL") with Environ::Get().GetRpcProtocol() for determining RPC protocol.
  • mooncake-store/src/real_client.cpp
    • Included environ.h.
  • mooncake-store/src/transfer_task.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_STORE_MEMCPY") with Environ::Get().GetStoreMemcpy().
  • mooncake-transfer-engine/src/config.cpp
    • Included environ.h.
    • Replaced numerous direct getenv() calls for various configuration parameters (e.g., MC_NUM_CQ_PER_CTX, MC_IB_PORT, MC_MAX_CQE_PER_CTX, MC_MTU, MC_HANDSHAKE_PORT, MC_LOG_LEVEL, MC_MIN_PRC_PORT, MC_FRAGMENT_RATIO, MC_IB_TC) with corresponding Environ::Get() methods.
    • Simplified parsing logic for several environment variables, leveraging the Environ class's type-safe getters.
  • mooncake-transfer-engine/src/topology.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_PATH_ROUNDROBIN") with Environ::Get().GetPathRoundrobin().
  • mooncake-transfer-engine/src/transfer_engine.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_USE_TENT") and getenv("MC_USE_TEV1") with Environ::Get().GetUseTent() and Environ::Get().GetUseTev1() respectively.
  • mooncake-transfer-engine/src/transfer_engine_impl.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_LEGACY_RPC_PORT_BINDING") with Environ::Get().GetLegacyRpcPortBinding().
    • Replaced direct getenv("MC_TCP_BIND_ADDRESS") with Environ::Get().GetTcpBindAddress().
    • Replaced direct getenv("MC_CXL_DEV_PATH") with Environ::Get().GetCxlDevPath().
    • Replaced direct getenv("MC_CUSTOM_TOPO_JSON") with Environ::Get().GetCustomTopoJson().
    • Replaced direct getenv("MC_FORCE_MNNVL") and getenv("MC_INTRANODE_NVLINK") with Environ::Get().GetForceMnnvl() and Environ::Get().GetIntranodeNvlink().
    • Replaced direct getenv("MC_FORCE_TCP") and getenv("MC_FORCE_HCA") with Environ::Get().GetForceTcp() and Environ::Get().GetForceHca().
    • Replaced direct getenv("MC_TE_METRIC") and getenv("MC_TE_METRIC_INTERVAL_SECONDS") with Environ::Get().GetTeMetric() and Environ::Get().GetTeMetricIntervalSeconds().
  • mooncake-transfer-engine/src/transfer_metadata.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_METADATA_CLUSTER_ID") with Environ::Get().GetMetadataClusterId().
  • mooncake-transfer-engine/src/transfer_metadata_plugin.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_REDIS_PASSWORD") with Environ::Get().GetRedisPassword().
    • Replaced direct getenv("MC_REDIS_DB_INDEX") with Environ::Get().GetRedisDbIndex() and simplified parsing logic.
  • mooncake-transfer-engine/src/transport/cxl_transport/cxl_transport.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_CXL_DEV_PATH") with Environ::Get().GetCxlDevPath().
    • Replaced direct getenv("MC_CXL_DEV_SIZE") with Environ::Get().GetCxlDevSize().
  • mooncake-transfer-engine/src/transport/hip_transport/hip_transport.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_HIP_NUM_STREAMS") with Environ::Get().GetHipNumStreams() and simplified parsing.
    • Replaced direct getenv("MC_HIP_NUM_EVENTS") with Environ::Get().GetHipNumEvents() and simplified parsing.
    • Replaced direct getenv("MC_USE_HIP_IPC") and getenv("MC_USE_NVLINK_IPC") with Environ::Get().GetUseHipIpc() and Environ::Get().GetUseNvlinkIpc().
  • mooncake-transfer-engine/src/transport/nvlink_transport/nvlink_transport.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_USE_NVLINK_IPC") with Environ::Get().GetUseNvlinkIpc().
  • mooncake-transfer-engine/src/transport/rpc_communicator/rpc_communicator.cpp
    • Included environ.h.
    • Replaced direct getenv("MC_RPC_PROTOCOL") with Environ::Get().GetRpcProtocol().
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request refactors environment variable access across the codebase by introducing a new Environ singleton class. The changes involve adding numerous getter methods and corresponding member variables to mooncake-common/include/environ.h and initializing them in mooncake-common/src/environ.cpp. Subsequently, all direct calls to std::getenv() for MC_ prefixed environment variables are replaced with calls to Environ::Get().Get<EnvVarName>() in various files, including mooncake-store/src/client_metric.cpp, client_service.cpp, ha_helper.cpp, master.cpp, transfer_task.cpp, and mooncake-transfer-engine/src/config.cpp, topology.cpp, transfer_engine.cpp, transfer_engine_impl.cpp, transfer_metadata.cpp, transfer_metadata_plugin.cpp, transport/cxl_transport/cxl_transport.cpp, transport/hip_transport/hip_transport.cpp, transport/nvlink_transport/nvlink_transport.cpp, and transport/rpc_communicator/rpc_communicator.cpp. Review comments highlight a missing closing brace in client_metric.cpp causing a compilation error, a broken fallback logic for MC_GID_INDEX to NCCL_IB_GID_INDEX in config.cpp due to the new Environ class's default return value, a risky C-style cast hiding a const_cast in cxl_transport.cpp when assigning cxl_dev_path, and a suggestion to change MC_STORE_MEMCPY and MC_STORE_USE_HUGEPAGE to return bool instead of std::string for consistency.

Comment on lines 569 to 570
} else {
LOG(WARNING)

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.

critical

There appears to be a missing closing brace } after the if (interval > 0) block on line 568. This is a syntax error that will cause a compilation failure.

        } else if (interval < 0) {
            LOG(WARNING)

Comment thread mooncake-transfer-engine/src/config.cpp Outdated
Comment on lines +40 to +46
int gid_index = env.GetGidIndex();
if (gid_index == 0) {
const char *nccl_gid = std::getenv("NCCL_IB_GID_INDEX");
if (nccl_gid) gid_index = atoi(nccl_gid);
}

const char *mtu_length_env = std::getenv("MC_MTU");
if (mtu_length_env) {
size_t val = atoi(mtu_length_env);
if (val == 512)
config.mtu_length = IBV_MTU_512;
else if (val == 1024)
config.mtu_length = IBV_MTU_1024;
else if (val == 2048)
config.mtu_length = IBV_MTU_2048;
else if (val == 4096)
config.mtu_length = IBV_MTU_4096;
else {
LOG(ERROR) << "Ignore value from environment variable MC_MTU, it "
"should be 512|1024|2048|4096";
exit(EXIT_FAILURE);
}
if (gid_index >= 0 && gid_index < 256)
config.gid_index = gid_index;

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.

high

The fallback logic for MC_GID_INDEX to NCCL_IB_GID_INDEX appears to be broken with this change. env.GetGidIndex() returns a default value of 3 if MC_GID_INDEX is not set, so the if (gid_index == 0) block is not executed, and the fallback to NCCL_IB_GID_INDEX is missed. Also, if a user explicitly sets MC_GID_INDEX=0, the current logic would incorrectly fall back to NCCL_IB_GID_INDEX.

The original logic of checking MC_GID_INDEX first, then NCCL_IB_GID_INDEX, should be preserved. A proper fix would be to handle this fallback logic inside the Environ class itself for better encapsulation.

if (!env_cxl_dev_path.empty()) {
LOG(INFO) << "MC_CXL_DEV_PATH: " << env_cxl_dev_path;
cxl_dev_path = (char *)env_cxl_dev_path;
cxl_dev_path = (char *)env_cxl_dev_path.c_str();

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.

medium

The C-style cast (char *) hides a const_cast. The member cxl_dev_path is a char*, but it's being assigned from env_cxl_dev_path.c_str() which returns a const char*. Modifying the string literal returned by c_str() is undefined behavior. It would be safer to change the type of cxl_dev_path to std::string or const char* to avoid this risky cast.

Comment thread mooncake-common/include/environ.h Outdated
Comment on lines +72 to +73
std::string GetStoreMemcpy() const { return store_memcpy_; }
std::string GetStoreUseHugepage() const { return store_use_hugepage_; }

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.

medium

The environment variables MC_STORE_MEMCPY and MC_STORE_USE_HUGEPAGE seem to be boolean flags. However, they are defined here to return std::string. For consistency with other boolean flags like GetUseHipIpc and to simplify usage, consider changing them to return bool and use GetBool in the implementation. This would also require changing the corresponding member variables store_memcpy_ and store_use_hugepage_ to bool.

@stmatengss stmatengss changed the title [Refactor] Centralize environment variable handling across components [TE][Store] refactor: centralize environment variable handling across components Feb 12, 2026
@stmatengss
stmatengss force-pushed the refactor/centralize-env-vars branch from f2389e3 to b220000 Compare February 12, 2026 06:43
@ykwd

ykwd commented Feb 13, 2026

Copy link
Copy Markdown
Collaborator

Glad that we now have a unified place to set and retrieve environment variables. I believe this will make things much more convenient for users.

@alogfans

Copy link
Copy Markdown
Collaborator

LGTM for TE part.

Comment thread mooncake-common/src/environ.cpp Resolved

@amd-arozanov amd-arozanov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@alogfans alogfans left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Before merging it, pls fix the build issue of Mooncake TE.

@stmatengss

Copy link
Copy Markdown
Collaborator Author

@copilot Please find a solution for this failing job. Use the logs, job definition, and any referenced files where the failure occurred. Keep your response focused on the solution and include code suggestions when appropriate

Copilot AI commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

@stmatengss I've opened a new pull request, #1665, to work on those changes. Once the pull request is ready, I'll request review from you.

@codecov-commenter

codecov-commenter commented Mar 16, 2026 •

Copy link
Copy Markdown

Copilot AI 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.

Pull request overview

Refactors Mooncake Transfer Engine and Mooncake Store to centralize environment-variable access through mooncake-common’s Environ singleton, reducing direct getenv() usage and consolidating parsing/defaults.

Changes:

  • Extend mooncake-common Environ with additional getters and wire mooncake_common into TE build/link paths.
  • Migrate multiple TE/store components (transports, topology, metadata, master/client paths) from getenv() to Environ::Get() getters.
  • Make CXL-related tests skip cleanly when CXL is unavailable.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
mooncake-transfer-engine/tests/cxl_transport_test.cpp Skip CXL tests when device/transport install isn’t available; minor test robustness tweaks.
mooncake-transfer-engine/src/transport/rpc_communicator/rpc_communicator.cpp Use Environ for MC_RPC_PROTOCOL.
mooncake-transfer-engine/src/transport/nvlink_transport/nvlink_transport.cpp Switch NVLink IPC/fabric decision to Environ.
mooncake-transfer-engine/src/transport/intranode_nvlink_transport/intranode_nvlink_transport.cpp Add non-CUDA stubs returning NotImplemented when USE_CUDA is off.
mooncake-transfer-engine/src/transport/hip_transport/hip_transport.cpp Switch HIP stream/event counts + IPC/fabric decision to Environ.
mooncake-transfer-engine/src/transport/cxl_transport/cxl_transport.cpp Use Environ for CXL device path/size; modernize cxl_dev_path storage.
mooncake-transfer-engine/src/transfer_metadata_plugin.cpp Use Environ for Redis password/DB index.
mooncake-transfer-engine/src/transfer_metadata.cpp Use Environ for metadata cluster ID prefix.
mooncake-transfer-engine/src/transfer_engine_impl.cpp Use Environ for multiple TE env toggles (RPC binding, CXL, topology JSON, transport forcing, metrics interval).
mooncake-transfer-engine/src/transfer_engine.cpp Use Environ to select TENT/TEv1 modes.
mooncake-transfer-engine/src/topology.cpp Use Environ for round-robin path selection.
mooncake-transfer-engine/src/config.cpp Refactor global config env parsing to use Environ getters.
mooncake-transfer-engine/src/CMakeLists.txt Link TE against mooncake_common.
mooncake-transfer-engine/include/transport/cxl_transport/cxl_transport.h Replace char* path with std::string, add member initialization defaults.
mooncake-transfer-engine/CMakeLists.txt Add mooncake-common subdir for standalone TE builds.
mooncake-store/tests/cxl_client_integration_test.cpp Skip some CXL tests when client creation fails / CXL unavailable.
mooncake-store/src/transfer_task.cpp Use Environ for MC_STORE_MEMCPY.
mooncake-store/src/real_client.cpp Include environ.h (prep for centralized env usage).
mooncake-store/src/master.cpp Use Environ for MC_RPC_PROTOCOL.
mooncake-store/src/ha_helper.cpp Use Environ for MC_STORE_CLUSTER_ID.
mooncake-store/src/client_service.cpp Use Environ for auto-discovery config and filters.
mooncake-store/src/client_metric.cpp Use Environ for client metrics enable/interval.
mooncake-p2p-store/build.sh Link mooncake_common and add its library path.
mooncake-common/src/environ.cpp Add cached parsing for many additional env vars.
mooncake-common/include/environ.h Add getters + stored fields for new env vars.
mooncake-common/common.cmake Make sccache optional when ENABLE_SCCACHE=ON, with warning if missing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread mooncake-common/include/environ.h Outdated
std::string GetTentConf() const { return tent_conf_; }
int GetTransferTimeout() const { return transfer_timeout_; }
bool GetUseHipIpc() const { return use_hip_ipc_; }
bool GetUseNvlinkIpc() const { return use_nvlink_ipc_; }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot fix it

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.

Fixed in c187d54. The nvlink_transport.cpp now uses GetNvlinkFabricMemEnabled() which returns true only when MC_USE_NVLINK_IPC is explicitly set to "0", preserving the tri-state contract. Also fixed the inverted supportFabricMem() logic in hip_transport.cpp and the GID index default/fallback handling.

Comment on lines +546 to +555
auto &env = Environ::Get();
std::string password_str = env.GetRedisPassword();

uint8_t db_index = 0;
const char *db_index_str = std::getenv("MC_REDIS_DB_INDEX");
if (db_index_str) {
try {
int index = std::stoi(db_index_str);
if (index >= 0 && index <= 255) {
db_index = static_cast<uint8_t>(index);
} else {
LOG(WARNING) << "Invalid Redis DB index: " << index
<< ", using default 0";
}
} catch (const std::exception &e) {
LOG(WARNING)
<< "Failed to parse MC_REDIS_DB_INDEX: " << e.what()
<< ", using default 0";
}
int db_index_val = env.GetRedisDbIndex();
if (db_index_val >= 0 && db_index_val <= 255) {
db_index = static_cast<uint8_t>(db_index_val);
} else if (db_index_val != 0) {
LOG(WARNING) << "Invalid Redis DB index: " << db_index_val
<< ", using default 0";
Comment thread mooncake-store/src/client_metric.cpp Resolved
// By default, use IPC mode
// Fabric memory is enabled only when MC_USE_HIP_IPC=false
bool hip_ipc = Environ::Get().GetUseHipIpc();
if (!hip_ipc) {
Comment on lines 58 to 60
static bool supportFabricMem() {
if (getenv("MC_USE_NVLINK_IPC")) return false;
if (Environ::Get().GetUseNvlinkIpc()) return false;

Comment on lines +39 to +44
int gid_index = env.GetGidIndex();
if (gid_index == 0) {
const char *nccl_gid = std::getenv("NCCL_IB_GID_INDEX");
if (nccl_gid) gid_index = atoi(nccl_gid);
}

const char *mtu_length_env = std::getenv("MC_MTU");
if (mtu_length_env) {
size_t val = atoi(mtu_length_env);
if (val == 512)
config.mtu_length = IBV_MTU_512;
else if (val == 1024)
config.mtu_length = IBV_MTU_1024;
else if (val == 2048)
config.mtu_length = IBV_MTU_2048;
else if (val == 4096)
config.mtu_length = IBV_MTU_4096;
else {
LOG(ERROR) << "Ignore value from environment variable MC_MTU, it "
"should be 512|1024|2048|4096";
exit(EXIT_FAILURE);
}
if (gid_index >= 0 && gid_index < 256) config.gid_index = gid_index;
Comment on lines 262 to 266
static std::string metadata_url_;
static UUID test_client_id_;
static inline bool is_cxl = false;
static inline bool cxl_available_ = true;
static int tmp_fd;

Copilot AI commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

@stmatengss I've opened a new pull request, #1686, to work on those changes. Once the pull request is ready, I'll request review from you.

@stmatengss
stmatengss requested a review from UNIDY2002 as a code owner March 18, 2026 05:20

@qoderai qoderai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

👋 Review Summary

Centralizing env handling into Environ and wiring it through TE, Store, EP, and Tent is a solid refactor that improves consistency and makes a lot of configuration paths easier to reason about. The added dynamic getter tests and CXL test hardening are good steps toward stability. The remaining concerns are mostly around diagnosability and a few brittle semantics for Redis and NVLink env-driven behavior.

🛡️ Key Risks & Issues

  • Redis DB index and auth configuration: The new Environ-backed Redis DB index handling in redis_connection.cpp, metastore.cpp, and transfer_metadata_plugin.cpp tightens validation but makes misconfigurations harder to see. Invalid MC_REDIS_DB_INDEX values now cause connection failures with little context, and there’s no explicit logging of the offending value. This can turn a small config error into an operational incident that looks like Redis unavailability.
  • NVLink fabric-mem opt-in semantics: GetNvlinkFabricMemEnabled and its use in nvlink_transport.cpp and PG’s connection_poller hinges on MC_USE_NVLINK_IPC being exactly "0" to enable fabric-mem. That’s a brittle magic-string convention that doesn’t align with the more general GetBool semantics you introduced, and makes it easy for operators to think "false" or "off" will flip the mode when they don’t.
  • Boolean env parsing surprises: The more permissive GetBool helper now treats a blank value and several tokens as false and logs warnings to stderr only. Because many critical toggles rely on this, and stderr isn’t always captured in production, a subtle mis-typed env value can quietly fall back to the default without durable diagnostics.

🧪 Verification Advice

  • For Redis-backed HA and metadata deployments, verify behavior under: valid MC_REDIS_DB_INDEX, out-of-range values (e.g. 256), and malformed strings, and confirm that logs clearly indicate configuration errors rather than generic connection failures.
  • For NVLink and HIP transports, exercise MC_USE_NVLINK_IPC and MC_USE_HIP_IPC combinations (unset, "0", "1", and common boolean tokens) and confirm fabric-mem vs IPC modes behave as intended in both TE and PG paths.
  • In a staging environment, run through a set of deliberately malformed boolean env values (for WITH_NVIDIA_PEERMEM, MC_DISABLE_GPU_DIRECT_RDMA, MC_USE_TENT, MC_USE_UBSHMEM_IPC) and check that the resulting mode, logs, and performance match expectations.

💡 Thoughts & Suggestions

  • Consider adding a small layer of explicit logging around Environ::GetRedisDbIndex and the Redis connection helpers so that invalid DB indices or auth combinations are clearly surfaced at startup.
  • It may be worthwhile to either document the MC_USE_NVLINK_IPC="0" convention very prominently or adjust GetNvlinkFabricMemEnabled to honor the same boolean vocabulary as GetBool, making operator-facing behavior more intuitive.
  • Overall the direction of the refactor is good; adding a handful of focused tests for the most critical env-driven behaviors (Redis, RPC protocol and timeouts, NVLink/HIP fabric-mem) would significantly increase confidence before rolling this widely.

🤖 Generated by Qoder • View workflow run

@@ -74,11 +75,10 @@ tl::expected<int, ErrorCode> ParsePositiveInt(std::string_view text,
}

tl::expected<int, ErrorCode> ResolveRedisDbIndex() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The new Redis DB index handling changes the failure mode in a way that could make configuration issues harder to diagnose.

In ResolveRedisDbIndex (mooncake-store/src/ha/common/redis/redis_connection.cpp:77), any value outside [0,255] now returns ErrorCode::INVALID_PARAMS based on Environ::Get().GetRedisDbIndex(), and ConnectRedis immediately propag that as a generic connection_error without logging which MC_REDIS_DB_INDEX value was problematic. Previously, the DB index was parsed directly from the env string and either coerced or at least validated with ParsePositiveInt, which gave clearer feedback.

For operators, a typo like MC_REDIS_DB_INDEX=256 or a negative value will now surface as "Redis connection failed" with no hint that the DB index itself is invalid. On a busy HA deployment this looks more like an availability incident than a simple configuration bug.

Consider adding an explicit log on INVALID_PARAMS that includes the raw DB index value, or tightening Environ::GetRedisDbIndex to validate the range and log once at startup. That way misconfigurations fail fast and leave a clear breadcrumb, while still keeping the stricter range checking you introduced.


🤖 Generated by Qoder • Fix in Qoder

@@ -315,7 +316,7 @@ static int getNumDevices() {
}

static bool supportFabricMem() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The tight coupling between MC_USE_NVLINK_IPC and the new GetNvlinkFabricMemEnabled() helper makes the fabric-mem opt-in semantics a bit brittle.

GetNvlinkFabricMemEnabled (mooncake-transfer-engine/include/environ.h:226–230) returns true only when the raw MC_USE_NVLINK_IPC string is exactly "0"; any other value (including common booleans like "false" or "off") is treated as "do not enable fabric-mem". That value is now fed into the NVLink supportFabricMem logic here and into the PyTorch backend’s connection_poller, so operators have to know about the special "0" magic literal to activate fabric memory.

Given that other flags now use GetBool with a richer vocabulary ("true", "on", "enable", etc.), this tri-state behavior is easy to misconfigure: someone might set MC_USE_NVLINK_IPC="false" expecting IPC to be disabled and fabric-mem to be enabled, but the code will quietly keep fabric-mem off. At scale that shows up as performance differences rather than a clear error.

It may be worth either documenting the "0" requirement very prominently, or relaxing GetNvlinkFabricMemEnabled to treat a recognized "false" token (per GetBool semantics) as fabric-mem opt-in as well, so the behavior matches operator intuition while still distinguishing unset from "off".


🤖 Generated by Qoder • Fix in Qoder

@qoderai qoderai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

👋 Review Summary

This refactor does a solid job of centralizing environment-variable handling into the Environ singleton across transfer engine, store, EP, and tent, fixing several legacy issues (GID index defaulting, NVLink fabric mem semantics, CXL test flakiness) while wiring mooncake_common into all the relevant build paths. The Environ API looks coherent, and most of the call sites now consistently rely on strongly-typed getters instead of ad-hoc getenv parsing.

🛡️ Key Risks & Issues

  • HIP/NVLink fabric-mem gating: the new supportFabricMem() logic in HipTransport now couples HIP fabric enablement to both GetUseHipIpc() and GetNvlinkFabricMemEnabled(). Because GetUseHipIpc() defaults to true and GetNvlinkFabricMemEnabled() only becomes true when MC_USE_NVLINK_IPC="0", the default "envs unset" case disables HIP fabric entirely, which may not match prior behavior or the intent described in the comment. This could silently prevent fabric-mem from being used in deployments that previously relied on MC_USE_HIP_IPC=0 without any NVLink-specific configuration.
  • Redis DB index consistency: store-side Redis connection and tent metastore both now depend on Environ’s GetRedisDbIndex(). The store HA path correctly rejects out-of-range DB indices with INVALID_PARAMS, while the tent metastore still silently falls back to REDIS_DEFAULT_DB_INDEX when the getter returns an invalid value. This is mostly a semantics issue, but it means misconfigured DB indices are handled differently depending on which component is reading them.
  • Dynamic vs cached env semantics: the PR introduces a mix of cached (constructor-time) and dynamic (per-call) getters. The tests for dynamic getters cover a good subset of new fields (CXL path, PKEY index, RPC timeouts, client metrics, hot cache), but the static vs dynamic distinction is subtle and not yet documented in tests, so future changes could inadvertently move a setting from one category to the other and surprise users who expect runtime changes to be visible.

🧪 Verification Advice

  • HIP/NVLink fabric: explicitly verify behavior under the main env combinations by running focused HIP transport tests or small integration checks with different settings for MC_USE_HIP_IPC and MC_USE_NVLINK_IPC (unset, "0", "1") and confirm that fabric mem is enabled only when desired. A small unit test around supportFabricMem() would make this safer.
  • Redis DB index and auth: add tests that set MC_REDIS_DB_INDEX to valid and invalid values and assert consistent handling between store HA and tent metastore, plus basic authentication coverage for MC_REDIS_USERNAME/MC_REDIS_PASSWORD to ensure the new %b calls behave correctly.
  • RPC protocol and timeout: run the existing RpcTimeoutTest plus a simple master+client setup with MC_RPC_PROTOCOL="rdma" to confirm that RDMA sockets are used uniformly by master, client, and RpcCommunicator, and that malformed timeout envs cleanly fall back to defaults.

💡 Thoughts & Suggestions

  • Consider documenting the intended matrix for HIP/NVLink IPC vs fabric mem in one place (even just in code comments near Environ getters), so future refactors have a clear behavioral target.
  • Where reasonable, prefer having invalid env values either fail fast or log at a single central point in Environ, rather than diverging behavior across components; this would make misconfiguration easier to diagnose.
  • Overall this is a valuable cleanup—completing the test coverage for the new Environ semantics (especially around transports, Redis, and hot cache) will make it much easier to safely evolve configuration knobs in subsequent changes.

🤖 Generated by Qoder • View workflow run

Comment on lines +330 to +333
static bool supportFabricMem() {
// By default, use IPC mode. Fabric memory is enabled only when
// MC_USE_HIP_IPC=0 or MC_USE_NVLINK_IPC=0 is explicitly set.
const char* hip_ipc = getenv("MC_USE_HIP_IPC");
const char* nvlink_ipc = getenv("MC_USE_NVLINK_IPC");

bool fabric_enabled = (hip_ipc && strcmp(hip_ipc, "0") == 0) ||
(nvlink_ipc && strcmp(nvlink_ipc, "0") == 0);

if (!fabric_enabled) {
bool hip_ipc = Environ::Get().GetUseHipIpc();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The refactor to Environ-based gating for HIP/NVLink fabric memory changes how mixed HIP/NVLink deployments behave and may not match the intent described in the comment.

Today supportFabricMem() requires both GetUseHipIpc() and GetNvlinkFabricMemEnabled() to line up as hip_ipc && !nvlink_fabric to disable fabric. In particular:

  • GetNvlinkFabricMemEnabled() only returns true when MC_USE_NVLINK_IPC is explicitly set to "0"; any other value (including unset) is treated as "fabric disabled".
  • GetUseHipIpc() defaults to true when MC_USE_HIP_IPC is unset.

Under those defaults, HIP fabric memory is always disabled even when the NVLink path is available and configured to use IPC by default. Previously, fabric could be enabled for HIP when either MC_USE_HIP_IPC=0 or MC_USE_NVLINK_IPC=0 was set, while leaving the common "unset" case in IPC mode. If the desired behavior is "only opt into HIP fabric when we explicitly turn off HIP IPC or explicitly opt into NVLink fabric", we may want to gate on the raw env state more directly, e.g.:

  • Treat MC_USE_NVLINK_IPC unset as "IPC mode" rather than "fabric disabled".
  • Require MC_USE_HIP_IPC=0 (explicit) to enable HIP fabric regardless of NVLink settings, instead of coupling HIP fabric strictly to NVLink fabric.

It would be good to double-check the intended matrix for HIP vs NVLink fabric/IPCs and consider a small unit test that exercises combinations of MC_USE_HIP_IPC and MC_USE_NVLINK_IPC so we don’t accidentally disable fabric on deployments that rely on it.


🤖 Generated by Qoder • Fix in Qoder

@qoderai qoderai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

👋 Review Summary

This is a substantial, well‑structured refactor that centralizes environment variable handling into Environ across transfer engine, store, EP/PG, Tent, HA, and build tooling. It also fixes a few subtle semantics (fabric‑mem opt‑in, GID index fallback, Redis DB index parsing) and hardens CXL‑related tests, which collectively improve correctness, debuggability, and CI stability.

🛡️ Key Risks & Issues

  • Fabric‑memory enablement (NVLink, HIP, UBSHMEM) now depends on new Environ getters like GetNvlinkFabricMemEnabled() and GetHipFabricMemEnabled(). The matrix tested in environ_test.cpp looks sound, but it’s worth being mindful that misconfigured envs could silently flip transports between IPC and fabric modes; staging coverage with representative env combinations will help avoid surprises.
  • Redis configuration is now strictly validated via Environ::GetRedisDbIndex() and propagated through HA and Tent metastore. This is an improvement, but operators should note that invalid MC_REDIS_DB_INDEX will yield -1 and log warnings; deployments relying on non‑default DBs should be checked after upgrading.
  • Store hot cache and hugepage settings, TCP/RPC protocol selection, and CXL availability are now more tightly controlled via env‑driven getters and new test skips. The behaviors I inspected are consistent with previous intent, but these are high‑impact knobs for performance and availability, so I’d recommend doing a focused smoke run in each major deployment profile (RDMA/TCP, HIP/NVLink, CXL/no‑CXL) when rolling this out.

🧪 Verification Advice

  • For transports, run end‑to‑end data‑path tests in environments that exercise both IPC and fabric‑mem modes (varying MC_USE_HIP_IPC, MC_USE_NVLINK_IPC, MC_USE_UBSHMEM_IPC) and confirm latency/throughput are in line with expectations and no transport unexpectedly falls back.
  • For Redis, configure MC_REDIS_DB_INDEX to a non‑zero value in a test cluster and verify that both HA components and Tent metastore talk to the intended logical DB; also try an invalid value to confirm the new error handling behaves as intended.
  • For store hot cache and RPC, run a load test with realistic MC_STORE_LOCAL_HOT_CACHE_* and MC_RPC_* envs and observe metrics/logs to ensure cache admission, eviction, and RPC timeouts align with existing SLOs.

💡 Thoughts & Suggestions

  • The Environ surface is getting quite rich; the added unit tests for dynamic getters and fabric‑mem matrix are very helpful. Over time, it might be worth grouping related getters (e.g., transport vs store vs HA) in small helper structs or namespaces to make it easier for new contributors to navigate.
  • The non‑CUDA stub for IntraNodeNvlinkTransport is a good defensive addition. If you expect non‑GPU builds to be common, a small test that asserts the NotImplemented behavior and log message would make this contract explicit and prevent regressions.
  • Overall the refactor is thoughtful and consistent; once the minor include duplication in RDMA context is cleaned up, this looks ready to ship after the targeted staging runs mentioned above.

🤖 Generated by Qoder • View workflow run

Comment on lines 32 to 35
#include "config.h"
#include "environ.h"
#include "cuda_alike.h"
#include "environ.h"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

In rdma_context.cpp the header "environ.h" is included twice near the top of the file (#include "environ.h" appears back‑to‑back after the existing includes). Functionally this is harmless because of include guards, but it’s unnecessary duplication in a hot path and makes it slightly harder to scan dependencies.

Since this PR is already focused on centralizing env handling, it would be cleaner to drop the redundant second include so RDMA context has a single, clear dependency on Environ.


🤖 Generated by Qoder • Fix in Qoder

This branch has not been deployed

No deployments
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.

10 participants