This is an automated email from the ASF dual-hosted git repository.
sdanilov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 8fda1b6a1c IGNITE-18007 MacOS support (#1272)
8fda1b6a1c is described below
commit 8fda1b6a1c523ef24974c27843005e7ca0568c70
Author: Semyon Danilov <[email protected]>
AuthorDate: Tue Nov 1 20:12:30 2022 +0300
IGNITE-18007 MacOS support (#1272)
---
modules/platforms/cpp/DEVNOTES.md | 26 +-
.../platforms/cpp/ignite/network/CMakeLists.txt | 17 +-
.../cpp/ignite/network/detail/linux/sockets.cpp | 30 ++
.../cpp/ignite/network/detail/linux/utils.cpp | 28 ++
.../network/detail/macos/macos_async_client.cpp | 171 +++++++++++
.../detail/macos/macos_async_worker_thread.cpp | 312 +++++++++++++++++++++
.../cpp/ignite/network/length_prefix_codec.cpp | 2 +-
modules/platforms/cpp/ignite/network/network.cpp | 8 +-
modules/platforms/cpp/ignite/schema/CMakeLists.txt | 33 ++-
.../platforms/cpp/tests/client-test/CMakeLists.txt | 2 +-
modules/platforms/cpp/tests/client-test/main.cpp | 41 +++
.../detail/{linux_process.h => unix_process.h} | 11 +-
.../platforms/cpp/tests/test-common/process.cpp | 8 +-
13 files changed, 665 insertions(+), 24 deletions(-)
diff --git a/modules/platforms/cpp/DEVNOTES.md
b/modules/platforms/cpp/DEVNOTES.md
index e0c7c243bb..36177f0309 100644
--- a/modules/platforms/cpp/DEVNOTES.md
+++ b/modules/platforms/cpp/DEVNOTES.md
@@ -17,7 +17,7 @@ mkdir cmake-build-debug
cd cmake-build-debug
conan install .. --build=missing -s build_type=Debug
cmake .. -DENABLE_TESTS=ON
-cmake --build . -j8
+cmake --build . -j8
```
### For Linux Developers
@@ -27,7 +27,17 @@ mkdir cmake-build-debug
cd cmake-build-debug
conan install .. --build=missing -s build_type=Debug -s
compiler.libcxx=libstdc++11
cmake .. -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
-cmake --build . -j8
+cmake --build . -j8
+```
+
+### For macOS Developers
+Building in debug mode with tests. In this dir:
+```shell
+mkdir cmake-build-debug
+cd cmake-build-debug
+conan install .. --build=missing -s build_type=Debug -s compiler.libcxx=libc++
+cmake .. -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
+cmake --build . -j8
```
### For Windows users
@@ -47,7 +57,17 @@ mkdir cmake-build-release
cd cmake-build-release
conan install .. --build=missing -s build_type=Release -s
compiler.libcxx=libstdc++11
cmake .. -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Release
-cmake --build . -j8
+cmake --build . -j8
+```
+
+### For macOS users
+Building in release mode without tests. In this dir:
+```shell
+mkdir cmake-build-release
+cd cmake-build-release
+conan install .. --build=missing -s build_type=Release -s
compiler.libcxx=libc++
+cmake .. -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Release
+cmake --build . -j8
```
## Run Tests
diff --git a/modules/platforms/cpp/ignite/network/CMakeLists.txt
b/modules/platforms/cpp/ignite/network/CMakeLists.txt
index d69976fce1..ad806b4ddc 100644
--- a/modules/platforms/cpp/ignite/network/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/network/CMakeLists.txt
@@ -37,7 +37,16 @@ if (WIN32)
detail/win/win_async_connecting_thread.cpp
detail/win/win_async_worker_thread.cpp
)
-else()
+elseif(APPLE)
+ list(APPEND SOURCES
+ detail/linux/connecting_context.cpp
+ detail/macos/macos_async_client.cpp
+ detail/linux/linux_async_client_pool.cpp
+ detail/macos/macos_async_worker_thread.cpp
+ detail/linux/sockets.cpp
+ detail/linux/utils.cpp
+ )
+elseif(UNIX)
list(APPEND SOURCES
detail/linux/connecting_context.cpp
detail/linux/linux_async_client.cpp
@@ -57,5 +66,11 @@ if (WIN32)
target_link_libraries(${TARGET} wsock32 ws2_32 iphlpapi crypt32)
endif()
+if (APPLE)
+ find_package(epoll-shim REQUIRED)
+ target_link_libraries(${TARGET} epoll-shim::epoll-shim)
+ add_compile_definitions(EPOLL_SHIM_NO_VARIADICS)
+endif()
+
set_target_properties(${TARGET} PROPERTIES VERSION ${CMAKE_PROJECT_VERSION})
set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE 1)
diff --git a/modules/platforms/cpp/ignite/network/detail/linux/sockets.cpp
b/modules/platforms/cpp/ignite/network/detail/linux/sockets.cpp
index 6bada64ce9..4558b4879e 100644
--- a/modules/platforms/cpp/ignite/network/detail/linux/sockets.cpp
+++ b/modules/platforms/cpp/ignite/network/detail/linux/sockets.cpp
@@ -28,6 +28,7 @@
namespace ignite::network::detail {
+#if defined(__linux__)
std::string get_socket_error_message(int error) {
std::stringstream res;
@@ -44,6 +45,35 @@ std::string get_socket_error_message(int error) {
return res.str();
}
+#elif defined(__APPLE__)
+std::string get_socket_error_message(int error) {
+ std::stringstream res;
+
+ res << "error_code=" << error;
+
+ if (error == 0)
+ return res.str();
+
+ char err_buf[1024] = {0};
+
+ const int err_res = strerror_r(error, err_buf, sizeof(err_buf));
+
+ switch (err_res) {
+ case 0:
+ res << ", msg=" << err_buf;
+ break;
+ case ERANGE:
+ // Buffer too small.
+ break;
+ default:
+ case EINVAL:
+ // Invalid error code.
+ break;
+ }
+
+ return res.str();
+}
+#endif
std::string get_last_socket_error_message() {
int last_error = errno;
diff --git a/modules/platforms/cpp/ignite/network/detail/linux/utils.cpp
b/modules/platforms/cpp/ignite/network/detail/linux/utils.cpp
index cfcbb9560b..ce35b9b5a9 100644
--- a/modules/platforms/cpp/ignite/network/detail/linux/utils.cpp
+++ b/modules/platforms/cpp/ignite/network/detail/linux/utils.cpp
@@ -21,6 +21,7 @@
namespace ignite::network::detail {
+#if defined(__linux__)
std::string get_last_system_error() {
int error_code = errno;
@@ -35,5 +36,32 @@ std::string get_last_system_error() {
return error_details;
}
+#elif defined(__APPLE__)
+std::string get_last_system_error() {
+ int error_code = errno;
+
+ std::string error_details;
+ if (error_code != 0) {
+ char err_buf[1024] = {0};
+
+ const int res = strerror_r(error_code, err_buf, sizeof(err_buf));
+
+ switch (res) {
+ case 0:
+ error_details.assign(err_buf);
+ break;
+ case ERANGE:
+ // Buffer too small.
+ break;
+ default:
+ case EINVAL:
+ // Invalid error code.
+ break;
+ }
+ }
+
+ return error_details;
+}
+#endif
} // namespace ignite::network::detail
diff --git
a/modules/platforms/cpp/ignite/network/detail/macos/macos_async_client.cpp
b/modules/platforms/cpp/ignite/network/detail/macos/macos_async_client.cpp
new file mode 100644
index 0000000000..49944edd7c
--- /dev/null
+++ b/modules/platforms/cpp/ignite/network/detail/macos/macos_async_client.cpp
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ignite/network/detail/linux/linux_async_client.h>
+
+
+#include <algorithm>
+#include <cstring>
+
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+// We don't want to use epoll-shim macro here, because we have other close()
functions.
+#undef close
+
+namespace ignite::network::detail {
+
+linux_async_client::linux_async_client(int fd, end_point addr, tcp_range range)
+ : m_state(state::CONNECTED)
+ , m_fd(fd)
+ , m_epoll(-1)
+ , m_id(0)
+ , m_addr(std::move(addr))
+ , m_range(std::move(range))
+ , m_send_packets()
+ , m_send_mutex()
+ , m_recv_packet(BUFFER_SIZE)
+ , m_close_err() {
+}
+
+linux_async_client::~linux_async_client() {
+ shutdown(std::nullopt);
+
+ close();
+}
+
+bool linux_async_client::shutdown(std::optional<ignite_error> err) {
+ std::lock_guard<std::mutex> lock(m_send_mutex);
+ if (m_state != state::CONNECTED)
+ return false;
+
+ m_close_err = err ? std::move(*err) : ignite_error("Connection closed by
application");
+ ::shutdown(m_fd, SHUT_RDWR);
+ m_state = state::SHUTDOWN;
+
+ return true;
+}
+
+bool linux_async_client::close() {
+ if (state::CLOSED == m_state)
+ return false;
+
+ stop_monitoring();
+ ::close(m_fd);
+ m_fd = -1;
+ m_state = state::CLOSED;
+
+ return true;
+}
+
+bool linux_async_client::send(std::vector<std::byte> &&data) {
+ std::lock_guard<std::mutex> lock(m_send_mutex);
+
+ m_send_packets.emplace_back(std::move(data));
+ if (m_send_packets.size() > 1)
+ return true;
+
+ return send_next_packet_locked();
+}
+
+bool linux_async_client::send_next_packet_locked() {
+ if (m_send_packets.empty())
+ return true;
+
+ auto &packet = m_send_packets.front();
+ auto dataView = packet.get_bytes_view();
+
+ ssize_t ret = ::send(m_fd, dataView.data(), dataView.size(), 0);
+ if (ret < 0)
+ return false;
+
+ packet.skip(static_cast<int32_t>(ret));
+
+ enable_send_notifications();
+
+ return true;
+}
+
+bytes_view linux_async_client::receive() {
+ ssize_t res = recv(m_fd, m_recv_packet.data(), m_recv_packet.size(), 0);
+ if (res < 0)
+ return {};
+
+ return {m_recv_packet.data(), size_t(res)};
+}
+
+bool linux_async_client::start_monitoring(int epoll0) {
+ if (epoll0 < 0)
+ return false;
+
+ epoll_event event{};
+ memset(&event, 0, sizeof(event));
+ event.data.ptr = this;
+ event.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP;
+
+ int res = epoll_ctl(epoll0, EPOLL_CTL_ADD, m_fd, &event);
+ if (res < 0)
+ return false;
+
+ m_epoll = epoll0;
+
+ return true;
+}
+
+void linux_async_client::stop_monitoring() //
NOLINT(readability-make-member-function-const)
+{
+ epoll_event event{};
+ memset(&event, 0, sizeof(event));
+
+ epoll_ctl(m_epoll, EPOLL_CTL_DEL, m_fd, &event);
+}
+
+void linux_async_client::enable_send_notifications() {
+ epoll_event event{};
+ memset(&event, 0, sizeof(event));
+ event.data.ptr = this;
+ event.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP;
+
+ epoll_ctl(m_epoll, EPOLL_CTL_MOD, m_fd, &event);
+}
+
+void linux_async_client::disable_send_notifications() {
+ epoll_event event{};
+ memset(&event, 0, sizeof(event));
+ event.data.ptr = this;
+ event.events = EPOLLIN | EPOLLRDHUP;
+
+ epoll_ctl(m_epoll, EPOLL_CTL_MOD, m_fd, &event);
+}
+
+bool linux_async_client::process_sent() {
+ std::lock_guard<std::mutex> lock(m_send_mutex);
+
+ if (m_send_packets.empty()) {
+ disable_send_notifications();
+
+ return true;
+ }
+
+ if (m_send_packets.front().empty())
+ m_send_packets.pop_front();
+
+ return send_next_packet_locked();
+}
+
+} // namespace ignite::network::detail
diff --git
a/modules/platforms/cpp/ignite/network/detail/macos/macos_async_worker_thread.cpp
b/modules/platforms/cpp/ignite/network/detail/macos/macos_async_worker_thread.cpp
new file mode 100644
index 0000000000..1ac114f378
--- /dev/null
+++
b/modules/platforms/cpp/ignite/network/detail/macos/macos_async_worker_thread.cpp
@@ -0,0 +1,312 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ignite/network/detail/linux/linux_async_worker_thread.h>
+#include <ignite/network/detail/linux/linux_async_client_pool.h>
+
+#include "../utils.h"
+
+#include <algorithm>
+#include <cstring>
+
+#include <netdb.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+// We don't want to use epoll-shim macro here, because we have other close()
functions.
+#undef close
+
+namespace ignite::network::detail {
+
+namespace {
+
+fibonacci_sequence<10> fibonacci10;
+
+} // ignite::network::detail
+
+linux_async_worker_thread::linux_async_worker_thread(linux_async_client_pool
&client_pool)
+ : m_client_pool(client_pool)
+ , m_stopping(true)
+ , m_epoll(-1)
+ , m_stop_event(-1)
+ , m_non_connected()
+ , m_current_connection()
+ , m_current_client()
+ , m_failed_attempts(0)
+ , m_last_connection_time()
+ , m_min_addrs(0)
+ , m_thread() {
+ memset(&m_last_connection_time, 0, sizeof(m_last_connection_time));
+}
+
+linux_async_worker_thread::~linux_async_worker_thread() {
+ stop();
+}
+
+void linux_async_worker_thread::start(size_t limit, std::vector<tcp_range>
addrs) {
+ m_epoll = epoll_create(1);
+ if (m_epoll < 0)
+ throw_last_system_error("Failed to create epoll instance");
+
+ m_stop_event = eventfd(0, EFD_NONBLOCK);
+ if (m_stop_event < 0) {
+ std::string msg = get_last_system_error("Failed to create stop event
instance", "");
+ epoll_shim_close(m_stop_event);
+ throw ignite_error(status_code::OS, msg);
+ }
+
+ epoll_event event{};
+ memset(&event, 0, sizeof(event));
+
+ event.events = EPOLLIN;
+
+ int res = epoll_ctl(m_epoll, EPOLL_CTL_ADD, m_stop_event, &event);
+ if (res < 0) {
+ std::string msg = get_last_system_error("Failed to create stop event
instance", "");
+ epoll_shim_close(m_stop_event);
+ epoll_shim_close(m_epoll);
+ throw ignite_error(status_code::OS, msg);
+ }
+
+ m_stopping = false;
+ m_failed_attempts = 0;
+ m_non_connected = std::move(addrs);
+
+ m_current_connection.reset();
+ m_current_client.reset();
+
+ if (!limit || limit > m_non_connected.size())
+ m_min_addrs = 0;
+ else
+ m_min_addrs = m_non_connected.size() - limit;
+
+ m_thread = std::thread(&linux_async_worker_thread::run, this);
+}
+
+void linux_async_worker_thread::stop() {
+ if (m_stopping)
+ return;
+
+ m_stopping = true;
+
+ int64_t value = 1;
+ ssize_t res = epoll_shim_write(m_stop_event, &value, sizeof(value));
+
+ (void)res;
+ assert(res == sizeof(value));
+
+ m_thread.join();
+
+ epoll_shim_close(m_stop_event);
+ epoll_shim_close(m_epoll);
+
+ m_non_connected.clear();
+ m_current_connection.reset();
+}
+
+void linux_async_worker_thread::run() {
+ while (!m_stopping) {
+ handle_new_connections();
+
+ if (m_stopping)
+ break;
+
+ handle_connection_events();
+ }
+}
+
+void linux_async_worker_thread::handle_new_connections() {
+ if (!should_initiate_new_connection())
+ return;
+
+ if (calculate_connection_timeout() > 0)
+ return;
+
+ addrinfo *addr = nullptr;
+ if (m_current_connection)
+ addr = m_current_connection->next();
+
+ if (!addr) {
+ // TODO: Use round-robin instead.
+ size_t idx = rand() % m_non_connected.size();
+ const tcp_range &range = m_non_connected.at(idx);
+
+ m_current_connection = std::make_unique<connecting_context>(range);
+ addr = m_current_connection->next();
+ if (!addr) {
+ m_current_connection.reset();
+ report_connection_error(end_point(), "Can not resolve a single
address from range: " + range.to_string());
+ ++m_failed_attempts;
+ return;
+ }
+ }
+
+ // Create a socket for connecting to server
+ int socket_fd = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
+ if (SOCKET_ERROR == socket_fd) {
+ report_connection_error(
+ m_current_connection->current_address(), "Socket creation failed: "
+ get_last_socket_error_message());
+ return;
+ }
+
+ try_set_socket_options(socket_fd, linux_async_client::BUFFER_SIZE, true,
true, true);
+ bool success = set_non_blocking_mode(socket_fd, true);
+ if (!success) {
+ report_connection_error(
+ m_current_connection->current_address(), "Can not make non-blocking
socket: " + get_last_socket_error_message());
+ return;
+ }
+
+ m_current_client = m_current_connection->to_client(socket_fd);
+ bool ok = m_current_client->start_monitoring(m_epoll);
+ if (!ok)
+ throw_last_system_error("Can not add file descriptor to epoll");
+
+ // Connect to server.
+ int res = connect(socket_fd, addr->ai_addr, addr->ai_addrlen);
+ if (SOCKET_ERROR == res) {
+ int last_error = errno;
+
+ clock_gettime(CLOCK_MONOTONIC, &m_last_connection_time);
+
+ if (last_error != EWOULDBLOCK && last_error != EINPROGRESS) {
+ handle_connection_failed("Failed to establish connection with the
host: " + get_socket_error_message(last_error));
+ return;
+ }
+ }
+}
+
+void linux_async_worker_thread::handle_connection_events() {
+ enum { MAX_EVENTS = 16 };
+ epoll_event events[MAX_EVENTS];
+
+ int timeout = calculate_connection_timeout();
+
+ int res = epoll_wait(m_epoll, events, MAX_EVENTS, timeout);
+
+ if (res <= 0)
+ return;
+
+ for (int i = 0; i < res; ++i) {
+ epoll_event ¤t_event = events[i];
+ auto client = static_cast<linux_async_client *>(current_event.data.ptr);
+ if (!client)
+ continue;
+
+ if (client == m_current_client.get()) {
+ if (current_event.events & (EPOLLRDHUP | EPOLLERR)) {
+ handle_connection_failed("Can not establish connection");
+ continue;
+ }
+
+ handle_connection_success(client);
+ }
+
+ if (current_event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) {
+ handle_connection_closed(client);
+ continue;
+ }
+
+ if (current_event.events & EPOLLIN) {
+ auto msg = client->receive();
+ if (msg.empty()) {
+ handle_connection_closed(client);
+ continue;
+ }
+
+ m_client_pool.handle_message_received(client->id(), msg);
+ }
+
+ if (current_event.events & EPOLLOUT) {
+ bool ok = client->process_sent();
+ if (!ok) {
+ handle_connection_closed(client);
+ continue;
+ }
+
+ m_client_pool.handle_message_sent(client->id());
+ }
+ }
+}
+
+void linux_async_worker_thread::report_connection_error(const end_point &addr,
std::string msg) {
+ ignite_error err(status_code::NETWORK, std::move(msg));
+ m_client_pool.handle_connection_error(addr, err);
+}
+
+void linux_async_worker_thread::handle_connection_failed(std::string msg) {
+ assert(m_current_client);
+
+ m_current_client->stop_monitoring();
+ m_current_client->close();
+
+ report_connection_error(m_current_client->address(), std::move(msg));
+
+ m_current_client.reset();
+ ++m_failed_attempts;
+}
+
+void linux_async_worker_thread::handle_connection_closed(linux_async_client
*client) {
+ client->stop_monitoring();
+
+ m_non_connected.push_back(client->get_range());
+
+ m_client_pool.close_and_release(client->id(), std::nullopt);
+}
+
+void linux_async_worker_thread::handle_connection_success(linux_async_client
*client) {
+ m_non_connected.erase(std::find(m_non_connected.begin(),
m_non_connected.end(), client->get_range()));
+
+ m_client_pool.add_client(std::move(m_current_client));
+
+ m_current_client.reset();
+ m_current_connection.reset();
+
+ m_failed_attempts = 0;
+
+ clock_gettime(CLOCK_MONOTONIC, &m_last_connection_time);
+}
+
+int linux_async_worker_thread::calculate_connection_timeout() const {
+ if (!should_initiate_new_connection())
+ return -1;
+
+ if (m_last_connection_time.tv_sec == 0)
+ return 0;
+
+ int timeout = int(fibonacci10.get_value(m_failed_attempts) * 1000);
+
+ timespec now{};
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ int passed =
+ int((now.tv_sec - m_last_connection_time.tv_sec) * 1000 + (now.tv_nsec
- m_last_connection_time.tv_nsec) / 1000000);
+
+ timeout -= passed;
+ if (timeout < 0)
+ timeout = 0;
+
+ return timeout;
+}
+
+bool linux_async_worker_thread::should_initiate_new_connection() const {
+ return !m_current_client && m_non_connected.size() > m_min_addrs;
+}
+
+} // namespace ignite::network::detail
diff --git a/modules/platforms/cpp/ignite/network/length_prefix_codec.cpp
b/modules/platforms/cpp/ignite/network/length_prefix_codec.cpp
index 28b5c0fd97..64e779f4a5 100644
--- a/modules/platforms/cpp/ignite/network/length_prefix_codec.cpp
+++ b/modules/platforms/cpp/ignite/network/length_prefix_codec.cpp
@@ -31,7 +31,7 @@ length_prefix_codec::length_prefix_codec()
data_buffer_owning length_prefix_codec::encode(data_buffer_owning &data) {
// Just pass data as is, because we encode message size in
// the application to avoid unnecessary re-allocations and copying.
- return std::move(data.consume_entirely());
+ return data.consume_entirely();
}
void length_prefix_codec::reset_buffer() {
diff --git a/modules/platforms/cpp/ignite/network/network.cpp
b/modules/platforms/cpp/ignite/network/network.cpp
index 342d78f57c..90f21f95ee 100644
--- a/modules/platforms/cpp/ignite/network/network.cpp
+++ b/modules/platforms/cpp/ignite/network/network.cpp
@@ -23,15 +23,17 @@
#ifdef _WIN32
# include "detail/win/win_async_client_pool.h"
-#else // Other. Assume Linux
+#else
# include "detail/linux/linux_async_client_pool.h"
#endif
namespace ignite::network {
std::shared_ptr<async_client_pool> make_async_client_pool(data_filters
filters) {
- auto pool =
-
std::make_shared<IGNITE_SWITCH_WIN_OTHER(detail::win_async_client_pool,
detail::linux_async_client_pool)>();
+ auto pool = std::make_shared<IGNITE_SWITCH_WIN_OTHER(
+ detail::win_async_client_pool,
+ detail::linux_async_client_pool
+ )>();
return std::make_shared<async_client_pool_adapter>(std::move(filters),
std::move(pool));
}
diff --git a/modules/platforms/cpp/ignite/schema/CMakeLists.txt
b/modules/platforms/cpp/ignite/schema/CMakeLists.txt
index 9b69be6cae..1c1f4fb5a0 100644
--- a/modules/platforms/cpp/ignite/schema/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/schema/CMakeLists.txt
@@ -19,21 +19,40 @@ project(ignite-schema)
set(TARGET ${PROJECT_NAME})
-add_library(${TARGET} STATIC
- big_decimal.cpp big_decimal.h
- big_integer.cpp big_integer.h
- binary_tuple_builder.cpp binary_tuple_builder.h
+set(SOURCES
+ big_decimal.cpp
+ big_integer.cpp
+ binary_tuple_builder.cpp
+ binary_tuple_parser.cpp
+ ignite_type.cpp
+)
+
+set(PUBLIC_HEADERS
+ big_decimal.h
+ big_integer.h
+ binary_tuple_builder.h
binary_tuple_header.h
- binary_tuple_parser.cpp binary_tuple_parser.h
+ binary_tuple_parser.h
binary_tuple_schema.h
column_info.h
ignite_date.h
ignite_date_time.h
ignite_time.h
ignite_timestamp.h
- ignite_type.cpp ignite_type.h
- types.h)
+ ignite_type.h
+ types.h
+)
+
+add_library(${TARGET} STATIC ${SOURCES})
target_link_libraries(${TARGET} ignite-common)
ignite_test(bignum_test bignum_test.cpp LIBS ${TARGET})
+
+install(TARGETS ${TARGET}
+ RUNTIME DESTINATION bin/
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+)
+
+ignite_install_headers(FILES ${PUBLIC_HEADERS} DESTINATION
${IGNITE_INCLUDEDIR}/schema)
diff --git a/modules/platforms/cpp/tests/client-test/CMakeLists.txt
b/modules/platforms/cpp/tests/client-test/CMakeLists.txt
index e1010ee6a3..56d3e52aac 100644
--- a/modules/platforms/cpp/tests/client-test/CMakeLists.txt
+++ b/modules/platforms/cpp/tests/client-test/CMakeLists.txt
@@ -29,7 +29,7 @@ set(SOURCES
)
add_executable(${TARGET} ${SOURCES})
-target_link_libraries(${TARGET} ignite-test-common ignite-client GTest::gtest)
+target_link_libraries(${TARGET} ignite-test-common ignite-client GTest::GTest)
set(TEST_TARGET IgniteClientTest)
add_test(NAME ${TEST_TARGET} COMMAND ${TARGET})
diff --git a/modules/platforms/cpp/tests/client-test/main.cpp
b/modules/platforms/cpp/tests/client-test/main.cpp
index fbe3a35086..2f47c3d146 100644
--- a/modules/platforms/cpp/tests/client-test/main.cpp
+++ b/modules/platforms/cpp/tests/client-test/main.cpp
@@ -22,8 +22,41 @@
#include <gtest/gtest.h>
#include <chrono>
+#include <csignal>
#include <thread>
+namespace {
+/** Shutdown handler that cleans up resources. */
+std::function<void(int)> shutdown_handler;
+
+/**
+ * Receives OS signal and handles it.
+ *
+ * @param signum Signal value.
+ */
+void signal_handler(int signum) {
+ shutdown_handler(signum);
+
+ signal(signum, SIG_DFL);
+
+ raise(signum);
+}
+}
+
+/**
+ * Sets process abortion (SIGABRT, SIGINT, SIGSEGV signals) handler.
+ *
+ * @param handler Abortion handler.
+ */
+void set_process_abort_handler(std::function<void(int)> handler) {
+ shutdown_handler = std::move(handler);
+
+ // Install signal handlers to clean up resources on early exit.
+ signal(SIGABRT, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGSEGV, signal_handler);
+}
+
/**
* Run prior to any other tests.
*/
@@ -42,7 +75,15 @@ void before_all() {
int main(int argc, char **argv) {
int res = 0;
before_all();
+
ignite::IgniteRunner runner;
+
+ set_process_abort_handler([&](int signal) {
+ std::cout << "Caught signal " << signal << " during tests" <<
std::endl;
+
+ runner.stop();
+ });
+
try {
runner.start(false);
diff --git a/modules/platforms/cpp/tests/test-common/detail/linux_process.h
b/modules/platforms/cpp/tests/test-common/detail/unix_process.h
similarity index 92%
rename from modules/platforms/cpp/tests/test-common/detail/linux_process.h
rename to modules/platforms/cpp/tests/test-common/detail/unix_process.h
index 4f85b94b3f..ad5678cfc8 100644
--- a/modules/platforms/cpp/tests/test-common/detail/linux_process.h
+++ b/modules/platforms/cpp/tests/test-common/detail/unix_process.h
@@ -26,6 +26,9 @@
#include <string>
#include <vector>
+#ifdef __APPLE__
+#include <csignal>
+#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -33,9 +36,9 @@
namespace ignite::detail {
/**
- * Implementation of CmdProcess for Windows.
+ * Implementation of CmdProcess for UNIX and UNIX-like systems.
*/
-class LinuxProcess : public ignite::CmdProcess {
+class UnixProcess : public ignite::CmdProcess {
public:
/**
* Constructor.
@@ -44,7 +47,7 @@ public:
* @param args Arguments.
* @param workDir Working directory.
*/
- LinuxProcess(std::string command, std::vector<std::string> args,
std::string workDir)
+ UnixProcess(std::string command, std::vector<std::string> args,
std::string workDir)
: m_running(false)
, m_command(std::move(command))
, m_args(std::move(args))
@@ -53,7 +56,7 @@ public:
/**
* Destructor.
*/
- ~LinuxProcess() override { kill(); }
+ ~UnixProcess() override { kill(); }
/**
* Start process.
diff --git a/modules/platforms/cpp/tests/test-common/process.cpp
b/modules/platforms/cpp/tests/test-common/process.cpp
index 9c2f9e6e39..a562c35d53 100644
--- a/modules/platforms/cpp/tests/test-common/process.cpp
+++ b/modules/platforms/cpp/tests/test-common/process.cpp
@@ -15,10 +15,10 @@
* limitations under the License.
*/
-#ifdef WIN32
+#ifdef _WIN32
# include "detail/win_process.h"
#else
-# include "detail/linux_process.h"
+# include "detail/unix_process.h"
#endif
#include "cmd_process.h"
@@ -30,11 +30,11 @@
namespace ignite {
std::unique_ptr<CmdProcess> CmdProcess::make(std::string command,
std::vector<std::string> args, std::string workDir) {
-#ifdef WIN32
+#ifdef _WIN32
return std::unique_ptr<CmdProcess>(new
detail::WinProcess(std::move(command), std::move(args), std::move(workDir)));
#else
return std::unique_ptr<CmdProcess>(
- new detail::LinuxProcess(std::move(command), std::move(args),
std::move(workDir)));
+ new detail::UnixProcess(std::move(command), std::move(args),
std::move(workDir)));
#endif
}