diff --git a/mooncake-store/src/transfer_task.cpp b/mooncake-store/src/transfer_task.cpp index 0b9cd1005b..18aaabd0d3 100644 --- a/mooncake-store/src/transfer_task.cpp +++ b/mooncake-store/src/transfer_task.cpp @@ -416,10 +416,17 @@ TransferSubmitter::TransferSubmitter(TransferEngine& engine, memcpy_pool_(std::make_unique()), fileread_pool_(std::make_unique(backend)), transfer_metric_(transfer_metric) { - // Read MC_STORE_MEMCPY environment variable, default to false (disabled) + // Read MC_STORE_MEMCPY environment variable. + // When not set, auto-detect based on transport type: + // - TCP-only environment: enable memcpy (avoids TCP loopback overhead) + // - RDMA/other transports: disable memcpy (RDMA is more efficient) const char* env_value = std::getenv("MC_STORE_MEMCPY"); if (env_value == nullptr) { - memcpy_enabled_ = false; // Default: disabled + memcpy_enabled_ = engine_.isTcpOnly(); + LOG(INFO) << "MC_STORE_MEMCPY not set, auto-detected: " + << (memcpy_enabled_ ? "TCP-only environment, memcpy enabled" + : "non-TCP transport available, memcpy " + "disabled"); } else { std::string env_str(env_value); // Convert to lowercase for case-insensitive comparison diff --git a/mooncake-transfer-engine/include/multi_transport.h b/mooncake-transfer-engine/include/multi_transport.h index 2666da4fe8..c556541bcd 100644 --- a/mooncake-transfer-engine/include/multi_transport.h +++ b/mooncake-transfer-engine/include/multi_transport.h @@ -55,6 +55,14 @@ class MultiTransport { Transport *getTransport(const std::string &proto); + /** + * @brief Check if TCP is the only installed transport. + * + * When only TCP transport is available (no RDMA, NVLink, etc.), + * local memcpy is preferred over TCP loopback for same-host transfers. + */ + bool isTcpOnly() const; + std::vector listTransports(); void *getBaseAddr(); diff --git a/mooncake-transfer-engine/include/transfer_engine.h b/mooncake-transfer-engine/include/transfer_engine.h index a825355746..65bc87417a 100644 --- a/mooncake-transfer-engine/include/transfer_engine.h +++ b/mooncake-transfer-engine/include/transfer_engine.h @@ -150,6 +150,14 @@ class TransferEngine { Transport* getTransport(const std::string& proto); + /** + * @brief Check if TCP is the only installed transport. + * + * When only TCP transport is available (no RDMA, NVLink, etc.), + * local memcpy is preferred over TCP loopback for same-host transfers. + */ + bool isTcpOnly() const; + int syncSegmentCache(const std::string& segment_name = ""); std::shared_ptr getMetadata(); diff --git a/mooncake-transfer-engine/include/transfer_engine_impl.h b/mooncake-transfer-engine/include/transfer_engine_impl.h index 72a5a59161..4016d82297 100644 --- a/mooncake-transfer-engine/include/transfer_engine_impl.h +++ b/mooncake-transfer-engine/include/transfer_engine_impl.h @@ -334,6 +334,8 @@ class TransferEngineImpl { return multi_transports_->getTransport(proto); } + bool isTcpOnly() const { return multi_transports_->isTcpOnly(); } + int syncSegmentCache(const std::string& segment_name = "") { return metadata_->syncSegmentCache(segment_name); } diff --git a/mooncake-transfer-engine/src/multi_transport.cpp b/mooncake-transfer-engine/src/multi_transport.cpp index c6fee5566e..812ce82102 100644 --- a/mooncake-transfer-engine/src/multi_transport.cpp +++ b/mooncake-transfer-engine/src/multi_transport.cpp @@ -461,6 +461,10 @@ Transport* MultiTransport::getTransport(const std::string& proto) { return transport_map_[proto].get(); } +bool MultiTransport::isTcpOnly() const { + return transport_map_.size() == 1 && transport_map_.count("tcp") == 1; +} + std::vector MultiTransport::listTransports() { std::vector transport_list; for (auto& entry : transport_map_) diff --git a/mooncake-transfer-engine/src/transfer_engine.cpp b/mooncake-transfer-engine/src/transfer_engine.cpp index aecc6d2ea8..4800c00535 100644 --- a/mooncake-transfer-engine/src/transfer_engine.cpp +++ b/mooncake-transfer-engine/src/transfer_engine.cpp @@ -179,6 +179,8 @@ Transport* TransferEngine::getTransport(const std::string& proto) { return impl_->getTransport(proto); } +bool TransferEngine::isTcpOnly() const { return impl_->isTcpOnly(); } + int TransferEngine::syncSegmentCache(const std::string& segment_name) { return impl_->syncSegmentCache(segment_name); } @@ -578,6 +580,15 @@ Transport* TransferEngine::getTransport(const std::string& proto) { return impl_->getTransport(proto); } +bool TransferEngine::isTcpOnly() const { + if (use_tent_) + // TENT already rejects TCP loopback transfers when MC_STORE_MEMCPY + // is disabled, so auto-enabling memcpy is unnecessary in TENT mode. + return false; + else + return impl_->isTcpOnly(); +} + int TransferEngine::syncSegmentCache(const std::string& segment_name) { if (use_tent_) return 0;