Skip to content

Commit c1255b7

Browse files
committed
refactor: introduce rdma_factory and make ENABLE_RDMA build optional
Add rdma_factory (make_rdma_sender / make_rdma_receiver) as a transport backend abstraction layer to eliminate #ifdef LIMESTONE_ENABLE_RDMA from business logic. ENABLE_RDMA=ON links rdma_comm_sender/receiver; ENABLE_RDMA=OFF uses null backends that return failure on initialize() to prevent silent no-ops. This completes the OSS preparation steps: - Introduce rdma_sender_base / rdma_receiver_base / rdma_send_stream_base as abstract transport interfaces - Add null backend (rdma/null/) and rdma_comm backend (rdma/rdma_comm/) - Remove #ifdef from datastore_impl.cpp and replica_server.cpp - Reorganize rdma/ source tree: null/ and rdma_comm/ subdirectories - Fix null_rdma_sender/receiver::initialize() to return failure when RDMA is disabled, making misconfiguration visible rather than silent - Guard RDMA-specific tests and test parameters with #ifdef LIMESTONE_ENABLE_RDMA across datastore_impl_test, replica_server_test, message_rdma_init_test, scenario_test, and datastore_replication_test - Add ENABLE_RDMA CMake option documentation to README.md - Add CMake Configure(PUT_ONLY=ON, ENABLE_RDMA=ON) task to tasks.json
1 parent 6f0040c commit c1255b7

41 files changed

Lines changed: 1245 additions & 164 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,14 @@ if (ENABLE_ALTIMETER)
8080
list(APPEND boost_components container)
8181
endif()
8282
find_package(Boost COMPONENTS ${boost_components} REQUIRED)
83-
# rdma_comm is always required because limestone core engine depends on RDMA communication.
84-
find_package(rdma_comm REQUIRED)
83+
84+
option(ENABLE_RDMA "Enable RDMA transport backend (requires rdma_comm library)" OFF)
85+
if(ENABLE_RDMA)
86+
find_package(rdma_comm REQUIRED)
87+
message(STATUS "RDMA transport backend: enabled")
88+
else()
89+
message(STATUS "RDMA transport backend: disabled (ENABLE_RDMA=OFF)")
90+
endif()
8591

8692
add_subdirectory(third_party) # should be before enable_testing()
8793

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ available options:
4747
* `-DRECOVERY_SORTER_KVSLIB=<library>` - select the eKVS library using at recovery process. (`LEVELDB` or `ROCKSDB` (default), case-insensitive)
4848
* `-DRECOVERY_SORTER_PUT_ONLY=OFF` - don't use (faster) put-only method at recovery process
4949
* `-DBUILD_REPLICATION_TESTS=ON` - (temporary) enable experimental replication tests (excluded by default)
50+
* `-DENABLE_RDMA=ON` - enable RDMA-based replication backend (requires rdma_comm library; OFF by default)
5051
* `-DENABLE_ALTIMETER=ON` - enable Altimeter event logging for WAL operations
5152
* for debugging only
5253
* `-DENABLE_SANITIZER=OFF` - disable sanitizers (requires `-DCMAKE_BUILD_TYPE=Debug`)

src/CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ file(GLOB SOURCES
22
"limestone/*.cpp"
33
"limestone/replication/*.cpp"
44
"limestone/partitioned_cursor/*.cpp"
5+
"limestone/rdma/rdma_socket_io.cpp"
56
)
67

8+
if(ENABLE_RDMA)
9+
file(GLOB RDMA_SOURCES "limestone/rdma/rdma_comm/*.cpp")
10+
else()
11+
file(GLOB RDMA_SOURCES "limestone/rdma/null/*.cpp")
12+
endif()
13+
list(APPEND SOURCES ${RDMA_SOURCES})
14+
715
add_library(${package_name}
816
${SOURCES}
917
)
@@ -29,7 +37,6 @@ endif()
2937

3038
target_link_libraries(${package_name}
3139
PUBLIC limestone-api
32-
PRIVATE rdma_comm
3340
PRIVATE Boost::boost
3441
PRIVATE Boost::filesystem
3542
PRIVATE glog::glog
@@ -39,6 +46,11 @@ target_link_libraries(${package_name}
3946
PRIVATE OpenSSL::Crypto
4047
)
4148

49+
if(ENABLE_RDMA)
50+
target_compile_definitions(${package_name} PRIVATE LIMESTONE_ENABLE_RDMA)
51+
target_link_libraries(${package_name} PRIVATE rdma_comm)
52+
endif()
53+
4254
if (ENABLE_ALTIMETER)
4355
target_link_libraries(${package_name}
4456
PRIVATE altimeter
@@ -65,9 +77,13 @@ target_link_libraries(limestone-impl
6577
INTERFACE nlohmann_json::nlohmann_json
6678
INTERFACE OpenSSL::SSL
6779
INTERFACE OpenSSL::Crypto
68-
INTERFACE rdma_comm
6980
)
7081

82+
if(ENABLE_RDMA)
83+
target_compile_definitions(limestone-impl INTERFACE LIMESTONE_ENABLE_RDMA)
84+
target_link_libraries(limestone-impl INTERFACE rdma_comm)
85+
endif()
86+
7187
# utils
7288
file(GLOB DBLOGUTIL_SOURCES
7389
"limestone/dblogutil/*.cpp"

src/limestone/datastore.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
#include <stdexcept>
2121
#include <future>
2222
#include <cerrno>
23+
#include <cstdint>
2324
#include <limits>
24-
#include <rdma_comm/channel_id_type.h>
25-
#include <rdma_comm/rdma_sender.h>
26-
#include <rdma_comm/unique_fd.h>
2725

2826
#include <boost/filesystem/fstream.hpp>
2927

@@ -1082,9 +1080,7 @@ void datastore::maybe_register_rdma_stream(log_channel& channel, std::size_t id)
10821080
if (socket_fd < 0) {
10831081
LOG_LP(FATAL) << "Failed to obtain socket fd for RDMA acknowledgements.";
10841082
}
1085-
rdma::communication::unique_fd ack_fd{socket_fd};
1086-
auto stream_result = acquire_fn(
1087-
static_cast<rdma::communication::channel_id_type>(id), std::move(ack_fd));
1083+
auto stream_result = acquire_fn(static_cast<std::uint16_t>(id), socket_fd);
10881084
if (! stream_result.status.success || stream_result.stream == nullptr) {
10891085
LOG_LP(FATAL) << "Failed to acquire RDMA send stream: "
10901086
<< stream_result.status.error_message;
@@ -1093,7 +1089,7 @@ void datastore::maybe_register_rdma_stream(log_channel& channel, std::size_t id)
10931089
};
10941090

10951091
if (impl_->has_rdma_stream_factory_for_test()) {
1096-
auto factory = impl_->get_rdma_stream_factory_for_test();
1092+
auto const* factory = impl_->get_rdma_stream_factory_for_test();
10971093
if (factory == nullptr) {
10981094
LOG_LP(FATAL) << "RDMA stream factory test hook missing.";
10991095
}
@@ -1107,19 +1103,17 @@ void datastore::maybe_register_rdma_stream(log_channel& channel, std::size_t id)
11071103
if (rdma_sender == nullptr || ! impl_->is_rdma_enabled()) {
11081104
return;
11091105
}
1110-
if (id > std::numeric_limits<rdma::communication::channel_id_type>::max()) {
1106+
if (id > std::numeric_limits<std::uint16_t>::max()) {
11111107
LOG_LP(FATAL) << "RDMA channel_id overflow: id=" << id;
11121108
}
11131109
auto* replica_connector = channel.get_impl()->get_replica_connector();
11141110
if (replica_connector == nullptr) {
11151111
LOG_LP(FATAL) << "replica_connector missing during RDMA stream registration.";
11161112
}
11171113
auto socket_fd = impl_->rdma_ack_fd_for_test().value_or(replica_connector->get_socket_fd());
1118-
acquire_stream(
1119-
[rdma_sender](rdma::communication::channel_id_type cid, rdma::communication::unique_fd fd) {
1120-
return rdma_sender->get_send_stream(cid, std::move(fd));
1121-
},
1122-
socket_fd);
1114+
acquire_stream([rdma_sender](std::uint16_t cid, int fd) {
1115+
return rdma_sender->get_send_stream(cid, fd);
1116+
}, socket_fd);
11231117
}
11241118

11251119
} // namespace limestone::api

src/limestone/datastore_impl.cpp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
#include <replication/message_error.h>
4545
#include <replication/message_rdma_init.h>
4646
#include <replication/message_rdma_init_ack.h>
47-
#include <rdma_comm/rdma_config.h>
47+
#include <rdma/rdma_factory.h>
4848
#include <manifest.h>
4949

5050
namespace limestone::api {
@@ -466,28 +466,17 @@ void datastore_impl::initialize_rdma_slots() {
466466
}
467467

468468
bool datastore_impl::initialize_rdma_sender(uint32_t slot_count, uint64_t remote_dma_address) {
469-
rdma::communication::rdma_config config{};
470-
auto capacity = static_cast<std::size_t>(slot_count);
471-
constexpr std::size_t chunk_size = 4096U;
472-
config.send_buffer.region_size_bytes = capacity * chunk_size;
473-
config.send_buffer.chunk_size_bytes = chunk_size;
474-
config.send_buffer.ring_capacity = capacity;
475-
config.remote_buffer = config.send_buffer;
476-
config.completion_queue_depth = 1024U;
477-
config.write_log_mode = rdma::communication::rdma_write_log_mode::full;
478-
479-
rdma_sender_ = std::make_unique<rdma::communication::rdma_sender>(config);
469+
rdma_sender_ = make_rdma_sender(slot_count);
480470
auto result = rdma_sender_->initialize(remote_dma_address);
481-
if (!result.success) {
471+
if (! result.success) {
482472
rdma_sender_.reset();
483-
LOG_LP(ERROR) << "rdma_sender::initialize() failed.";
473+
LOG_LP(ERROR) << "rdma_sender::initialize() failed: " << result.error_message;
484474
return false;
485475
}
486-
487476
return true;
488477
}
489478

490-
rdma::communication::rdma_sender* datastore_impl::get_rdma_sender() const noexcept {
479+
rdma_sender_base* datastore_impl::get_rdma_sender() const noexcept {
491480
return rdma_sender_.get();
492481
}
493482

@@ -506,7 +495,7 @@ bool datastore_impl::shutdown_rdma_sender() noexcept {
506495
return true;
507496
}
508497

509-
void datastore_impl::set_rdma_sender_for_test(std::unique_ptr<rdma::communication::rdma_sender> sender) noexcept {
498+
void datastore_impl::set_rdma_sender_for_test(std::unique_ptr<rdma_sender_base> sender) noexcept {
510499
rdma_sender_ = std::move(sender);
511500
}
512501

@@ -516,13 +505,11 @@ void datastore_impl::set_log_channel_connector_factory_for_test(
516505
}
517506

518507
void datastore_impl::set_rdma_stream_factory_for_test(
519-
std::function<rdma::communication::rdma_sender::stream_acquire_result(
520-
rdma::communication::channel_id_type, rdma::communication::unique_fd)> factory) noexcept {
508+
std::function<rdma_sender_base::stream_acquire_result(std::uint16_t, int)> factory) noexcept {
521509
rdma_stream_factory_for_test_ = std::move(factory);
522510
}
523511

524-
std::function<rdma::communication::rdma_sender::stream_acquire_result(
525-
rdma::communication::channel_id_type, rdma::communication::unique_fd)> const*
512+
std::function<rdma_sender_base::stream_acquire_result(std::uint16_t, int)> const*
526513
datastore_impl::get_rdma_stream_factory_for_test() const noexcept {
527514
if (rdma_stream_factory_for_test_) {
528515
return &rdma_stream_factory_for_test_;

src/limestone/datastore_impl.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#include "manifest.h"
3131
#include "replication/replica_connector.h"
3232
#include "replication/replication_endpoint.h"
33-
#include <rdma_comm/rdma_sender.h>
33+
#include <rdma/rdma_sender_base.h>
3434

3535
namespace limestone::api {
3636

@@ -121,7 +121,7 @@ class datastore_impl {
121121
* @brief Get RDMA sender instance if initialized.
122122
* @return pointer to RDMA sender or nullptr if not available.
123123
*/
124-
[[nodiscard]] rdma::communication::rdma_sender* get_rdma_sender() const noexcept;
124+
[[nodiscard]] rdma_sender_base* get_rdma_sender() const noexcept;
125125

126126
// Getter for migration_info_
127127
[[nodiscard]] const std::optional<manifest::migration_info>& get_migration_info() const noexcept;
@@ -224,7 +224,7 @@ class datastore_impl {
224224
* @param sender RDMA sender ownership to set for testing.
225225
* @note Test-only; do not use in production code.
226226
*/
227-
void set_rdma_sender_for_test(std::unique_ptr<rdma::communication::rdma_sender> sender) noexcept;
227+
void set_rdma_sender_for_test(std::unique_ptr<rdma_sender_base> sender) noexcept;
228228

229229
/**
230230
* @brief Test hook to override replica connector factory for log channels.
@@ -240,11 +240,9 @@ class datastore_impl {
240240
* @note Test-only; do not use in production code.
241241
*/
242242
void set_rdma_stream_factory_for_test(
243-
std::function<rdma::communication::rdma_sender::stream_acquire_result(
244-
rdma::communication::channel_id_type, rdma::communication::unique_fd)> factory) noexcept;
243+
std::function<rdma_sender_base::stream_acquire_result(std::uint16_t, int)> factory) noexcept;
245244

246-
[[nodiscard]] std::function<rdma::communication::rdma_sender::stream_acquire_result(
247-
rdma::communication::channel_id_type, rdma::communication::unique_fd)> const*
245+
[[nodiscard]] std::function<rdma_sender_base::stream_acquire_result(std::uint16_t, int)> const*
248246
get_rdma_stream_factory_for_test() const noexcept;
249247

250248
/**
@@ -298,14 +296,13 @@ class datastore_impl {
298296
void initialize_rdma_slots();
299297

300298
// RDMA sender owned by master for RDMA replication path.
301-
std::unique_ptr<rdma::communication::rdma_sender> rdma_sender_{};
299+
std::unique_ptr<rdma_sender_base> rdma_sender_{};
302300

303301
// Test hook: factory to override log channel connector creation.
304302
std::function<std::unique_ptr<replication::replica_connector>()> log_channel_connector_factory_for_test_{};
305303

306304
// Test hook: factory to override RDMA stream acquisition.
307-
std::function<rdma::communication::rdma_sender::stream_acquire_result(
308-
rdma::communication::channel_id_type, rdma::communication::unique_fd)> rdma_stream_factory_for_test_{};
305+
std::function<rdma_sender_base::stream_acquire_result(std::uint16_t, int)> rdma_stream_factory_for_test_{};
309306

310307
// Test hook: override ack fd used for RDMA registration.
311308
std::optional<int> rdma_ack_fd_for_test_{};

src/limestone/log_channel_impl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
#include "replication/message_log_entries.h"
99
#include "replication/replication_message.h"
1010
#include "replication/socket_io.h"
11-
#include "replication/rdma_socket_io.h"
11+
#include "rdma/rdma_socket_io.h"
1212
#include "limestone/api/datastore.h"
1313
#include "limestone/logging.h"
1414
#include "logging_helper.h"
1515

1616
namespace limestone::api {
1717

18+
using limestone::replication::rdma_send_stream_base;
19+
1820
namespace {
1921

2022
constexpr auto rdma_flush_timeout = std::chrono::milliseconds{30000};
@@ -164,7 +166,7 @@ std::future<void> log_channel_impl::flush_rdma_stream_async() {
164166
return fut;
165167
}
166168

167-
void log_channel_impl::set_rdma_send_stream(std::unique_ptr<rdma::communication::rdma_send_stream> stream) noexcept {
169+
void log_channel_impl::set_rdma_send_stream(std::unique_ptr<rdma_send_stream_base> stream) noexcept {
168170
std::lock_guard<std::mutex> lock(mtx_replica_connector_);
169171
rdma_send_stream_ = std::move(stream);
170172
}

src/limestone/log_channel_impl.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include <vector>
2222
#include <boost/asio.hpp>
2323
#include <future>
24-
#include <rdma_comm/rdma_sender.h>
24+
#include <rdma/rdma_send_stream_base.h>
2525
#include <boost/filesystem.hpp>
2626

2727
#include "limestone/api/blob_id_type.h"
@@ -30,7 +30,6 @@
3030
#include "limestone/status.h"
3131
#include "replication/replica_connector.h"
3232
#include "replication/socket_io.h"
33-
#include "replication/rdma_socket_io.h"
3433
#include "replication/message_log_entries.h"
3534

3635
namespace limestone::api {
@@ -104,7 +103,7 @@ class log_channel_impl {
104103
* @brief Sets RDMA send stream for replication.
105104
* @param stream RDMA stream instance to take ownership of.
106105
*/
107-
void set_rdma_send_stream(std::unique_ptr<rdma::communication::rdma_send_stream> stream) noexcept;
106+
void set_rdma_send_stream(std::unique_ptr<replication::rdma_send_stream_base> stream) noexcept;
108107

109108
/**
110109
* @brief Sets the datastore reference used for BLOB operations on the RDMA path.
@@ -132,7 +131,7 @@ class log_channel_impl {
132131

133132
private:
134133
std::unique_ptr<replication::replica_connector> replica_connector_;
135-
std::unique_ptr<rdma::communication::rdma_send_stream> rdma_send_stream_;
134+
std::unique_ptr<replication::rdma_send_stream_base> rdma_send_stream_;
136135
replication::socket_io rdma_serializer_io_;
137136
datastore* datastore_{nullptr};
138137
std::unique_ptr<boost::asio::thread_pool> ack_thread_pool_;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2022-2025 Project Tsurugi.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include <rdma/null_rdma_receiver.h>
17+
18+
namespace limestone::replication {
19+
20+
rdma_receiver_base::operation_result null_rdma_receiver::initialize(
21+
rdma_receive_handler /*handler*/) noexcept {
22+
return {false, "RDMA is not enabled in this build (ENABLE_RDMA=OFF)"};
23+
}
24+
25+
rdma_receiver_base::operation_result null_rdma_receiver::shutdown() noexcept {
26+
return {true, ""};
27+
}
28+
29+
rdma_receiver_base::operation_result null_rdma_receiver::register_channel(
30+
std::uint16_t /*channel_id*/,
31+
int /*ack_socket*/) noexcept {
32+
return {true, ""};
33+
}
34+
35+
std::optional<std::uint64_t> null_rdma_receiver::get_dma_address() const noexcept {
36+
return std::nullopt;
37+
}
38+
39+
} // namespace limestone::replication
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2022-2025 Project Tsurugi.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include <rdma/null_rdma_send_stream.h>
17+
18+
namespace limestone::replication {
19+
20+
rdma_send_stream_base::send_result null_rdma_send_stream::send_bytes(
21+
std::vector<std::uint8_t> const& /*payload*/,
22+
std::size_t /*offset*/,
23+
std::size_t length) noexcept {
24+
return {true, "", length};
25+
}
26+
27+
rdma_send_stream_base::send_result null_rdma_send_stream::send_all_bytes(
28+
std::vector<std::uint8_t> const& /*payload*/,
29+
std::size_t /*offset*/,
30+
std::size_t length) noexcept {
31+
return {true, "", length};
32+
}
33+
34+
rdma_send_stream_base::flush_result null_rdma_send_stream::flush(
35+
std::chrono::milliseconds /*timeout*/) noexcept {
36+
return {true, ""};
37+
}
38+
39+
} // namespace limestone::replication

0 commit comments

Comments
 (0)