Skip to content

Conversation

@Erixonich
Copy link
Contributor

https://issues.apache.org/jira/browse/IGNITE-27056

Thank you for submitting the pull request.

To streamline the review process of the patch and ensure better code quality
we ask both an author and a reviewer to verify the following:

The Review Checklist

  • Formal criteria: TC status, codestyle, mandatory documentation. Also make sure to complete the following:
    - There is a single JIRA ticket related to the pull request.
    - The web-link to the pull request is attached to the JIRA ticket.
    - The JIRA ticket has the Patch Available state.
    - The description of the JIRA ticket explains WHAT was made, WHY and HOW.
    - The pull request title is treated as the final commit message. The following pattern must be used: IGNITE-XXXX Change summary where XXXX - number of JIRA issue.
  • Design: new code conforms with the design principles of the components it is added to.
  • Patch quality: patch cannot be split into smaller pieces, its size must be reasonable.
  • Code quality: code is clean and readable, necessary developer documentation is added if needed.
  • Tests code quality: test set covers positive/negative scenarios, happy/edge cases. Tests are effective in terms of execution time and resources.

Notes

@Erixonich Erixonich requested a review from isapego as a code owner November 25, 2025 20:27
# Conflicts:
#	modules/platforms/cpp/ignite/client/detail/node_connection.h

std::optional<std::chrono::time_point<std::chrono::steady_clock>> timeout{};
if (m_configuration.get_operation_timeout().count() > 0) {
timeout = std::chrono::steady_clock::now() + m_configuration.get_operation_timeout();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In java client there is an optimization for calling analog of ::now(). I am not aware of performance of this method. Should we research if similiar optimisation is required?

Copy link
Contributor

Choose a reason for hiding this comment

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

Why? What exactly should be optimized here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TLDR:
I was under impression that java's System.currentTimeMillis() and steady_clock::now() have similar implementation and drawbacks. But learning a bit deeper revealed to me that system_clock::now() should be analogous to System.currentTimeMillis().


as I said I don't know any performance issues of this method. In java case there were some issues with analogous System.currentTimeMillis() on windows platform. That could be a reason why in ignite codebase we have org.apache.ignite.internal.util.FastTimestamps#coarseCurrentTimeMillis.

what optimization could be (if calling std::chrono::steady_clock::now() would be slower than we can afford). We spawn a thread which updates atomic value every X seconds. Instead of calling ::now() we read from atomic variable. As I googled a bit calling steady_clock::now() doesn't switch context from userspace to kernelspace (on opposing of calling system_clock::now()).

I am pretty sure that we don't want to do it right now, but maybe small task to research performance impact of calling ::now on each request.

using namespace ignite;

const std::vector<std::string> DEFAULT_VERSIONS = {"9.1.0", "9.1.1", "9.1.2", "9.1.3", "9.1.4"};
const std::vector<std::string> DEFAULT_VERSIONS = {"3.0.0"};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

unrelated to this ticket but mistake I made in previous PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about 3.1.0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@isapego isapego requested a review from Copilot November 26, 2025 23:46
Copilot finished reviewing on behalf of isapego November 26, 2025 23:48
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds request timeout support to the C++ client for Apache Ignite. The implementation allows clients to specify an operation timeout that applies to individual network operations, causing them to fail if the server doesn't respond within the specified time.

Key changes:

  • Adds operation_timeout configuration parameter to ignite_client_configuration
  • Implements timeout tracking in node_connection using pending request metadata
  • Creates a fake server test infrastructure to simulate timeout scenarios
  • Adds new error code CLIENT_OPERATION_TIMEOUT for timeout failures

Reviewed changes

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

Show a summary per file
File Description
modules/platforms/cpp/ignite/client/ignite_client_configuration.h Adds operation timeout configuration getter/setter with validation
modules/platforms/cpp/ignite/common/error_codes.h Adds CLIENT_OPERATION_TIMEOUT error code
modules/api/src/main/java/org/apache/ignite/lang/ErrorGroups.java Adds corresponding Java error code
modules/platforms/cpp/ignite/client/detail/node_connection.h Adds pending_request structure with timeout metadata
modules/platforms/cpp/ignite/client/detail/node_connection.cpp Implements timeout handling logic with periodic checks
modules/platforms/cpp/tests/fake_server/* New fake server infrastructure for testing timeout scenarios
modules/platforms/cpp/tests/fake_server/connection_test.cpp Tests for handshake and timeout functionality
modules/platforms/cpp/ignite/protocol/buffer_adapter.h Refactors magic number to use constant
modules/platforms/cpp/tests/client-test/main.cpp Temporary bypass of connection check (likely for testing)
modules/platforms/cpp/tests/compatibility-tests/main.cpp Updates default version for compatibility testing

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

std::vector<int64_t> keys_for_erasure;

for (auto& [id, req] : m_request_handlers) {
if (req.timeouts_at > now) {
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The comparison logic is inverted. This should be req.timeouts_at < now to check if the request has timed out (i.e., the timeout time point is in the past). Currently, it marks requests as timed out when they haven't expired yet.

Suggested change
if (req.timeouts_at > now) {
if (req.timeouts_at < now) {

Copilot uses AI. Check for mistakes.

std::stringstream ss;
ss << "Operation timeout [req_id=" << id << "]";
auto res = req.handler->set_error(ignite_error(error::code::CLIENT_OPERATION_TIMEOUT,ss.str()));
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Missing space after comma in function call. Should be ss.str())ss.str()) with proper spacing: CLIENT_OPERATION_TIMEOUT, ss.str().

Suggested change
auto res = req.handler->set_error(ignite_error(error::code::CLIENT_OPERATION_TIMEOUT,ss.str()));
auto res = req.handler->set_error(ignite_error(error::code::CLIENT_OPERATION_TIMEOUT, ss.str()));

Copilot uses AI. Check for mistakes.

std::optional<std::chrono::time_point<std::chrono::steady_clock>> timeout{};
if (m_configuration.get_operation_timeout().count() > 0) {
timeout = std::chrono::steady_clock::now() + m_configuration.get_operation_timeout();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why? What exactly should be optimized here?

Comment on lines +225 to +227
std::stringstream ss;
ss << "Operation timeout [req_id=" << id << "]";
auto res = req.handler->set_error(ignite_error(error::code::CLIENT_OPERATION_TIMEOUT,ss.str()));
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also log it as a warning here.

std::vector<int64_t> keys_for_erasure;

for (auto& [id, req] : m_request_handlers) {
if (req.timeouts_at > now) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems wrong. Do tests pass?

Suggested change
if (req.timeouts_at > now) {
if (req.timeouts_at < now) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will add a test which would fail with suc incorrect code. Thats left as artifact of refactoring.

{
std::lock_guard lock(m_request_handlers_mutex);

std::vector<int64_t> keys_for_erasure;
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's try avoiding additional memory allocation here. Let's erase values as we move through the map. We hold the lock anyway. It can be done with iterator:

auto it = map.begin();
while (it != map.end()) {
  if (something) {
    it = map.erase(it);
    continue;
  }
  ++it;
}

/**
* Default operation
*/
static constexpr std::chrono::milliseconds DEFAULT_OPERATION_TIMEOUT = std::chrono::milliseconds(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
static constexpr std::chrono::milliseconds DEFAULT_OPERATION_TIMEOUT = std::chrono::milliseconds(0);
static constexpr std::chrono::milliseconds DEFAULT_OPERATION_TIMEOUT{0};

Comment on lines +1 to +3
//
// Created by Ed on 21.11.2025.
//
Copy link
Contributor

Choose a reason for hiding this comment

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

License

Comment on lines +1 to +5
//
// Created by Ed on 25.11.2025.
//

#include "response_action.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Empty file? Let's remove.

Comment on lines +1 to +5
//
// Created by Ed on 21.11.2025.
//

#include "fake_server.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Empty file, let's remove.

Comment on lines +1 to +3
//
// Created by Ed on 25.11.2025.
//
Copy link
Contributor

Choose a reason for hiding this comment

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

License.

Comment on lines +23 to +25
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this implementation for Linux only?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants