Skip to content

Merge master in 5.7.0#1476

Merged
dmitriyrazboev merged 4 commits into
5.7.0from
master
Jun 4, 2026
Merged

Merge master in 5.7.0#1476
dmitriyrazboev merged 4 commits into
5.7.0from
master

Conversation

@dmitriyrazboev

@dmitriyrazboev dmitriyrazboev commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

prepare 5.7.0 client for release
backport changes from master
merge from master to 5.7.0 branch

…nd OpenSSL 3.x [HZ-5424] (#1464)

Closes #1463

## Summary

- The Boost 1.83.0 + OpenSSL 3.x matrix entry of the `nightly-Windows`
workflow fails to compile `rfc2818_verification.ipp`: `error C2027: use
of undefined type 'asn1_string_st'` (followed by a cascading `C2660` on
`memcmp`).
- The client never references `boost::asio::ssl::rfc2818_verification`;
it uses the modern `host_name_verification`
(`hazelcast/src/hazelcast/util/util.cpp`). The broken `.ipp` was being
dragged in transitively through the umbrella `<boost/asio/ssl.hpp>`
include in three internal socket headers.
- Replaced the umbrella include in `BaseSocket.h`, `SSLSocket.h`, and
`SocketFactory.h` with the specific subheaders the codebase actually
uses (`context.hpp`, `error.hpp`, `host_name_verification.hpp`,
`stream.hpp`) — matching the include pattern already used in `util.cpp`.
This avoids `rfc2818_verification.hpp` entirely.

## Root cause

In Boost 1.83.0, `<boost/asio/ssl.hpp>` lists
`<boost/asio/ssl/rfc2818_verification.hpp>` among its includes. In
Boost.Asio's default header-only mode that pulls in
`rfc2818_verification.ipp`, whose hostname-matching code dereferences
`ASN1_STRING` fields directly (`domain->data`, `domain->length`).
OpenSSL 3.0 made `ASN1_STRING` an opaque type whose layout is no longer
exposed by the public headers, so MSVC refuses to compile the field
accesses (hence `C2027`; the `C2660` is a follow-on because
`domain->data` collapses to a non-pointer expression). GCC/Clang on
Linux/macOS happen to accept the opaque-struct dereference more
leniently on this path, which is why only the Windows + MSVC + OpenSSL
3.x combination breaks.

Upstream Boost dropped `rfc2818_verification` from
`<boost/asio/ssl.hpp>` after 1.83.0; it is no longer present in 1.90.0.
That is why only the 1.83.0 matrix entry is affected.

Tracking: HZ-5424
…side the row loop [HZ-5424] (#1471)

Fixes #1470

## Summary

- `SqlTest.select` was iterating over 4 096 SQL rows and calling
`EXPECT_THROW` three times per row to verify `get_object()` raises
`index_out_of_bounds` / `illegal_argument`. That is **~12 000 C++
exception throws** per test run.
- On Windows the CI step runs ProcDump as a debugger (`procdump -e -ma
-w client_test.exe`). Every C++ `throw` raises SEH code `0xE06D7363`;
the OS delivers this as a *first-chance debug event* to ProcDump
**before** the C++ `catch` handler can run. ProcDump logs
`[HH:MM:SS]Exception: E06D7363.?AVindex_out_of_bounds@...`, then calls
`ContinueDebugEvent()` — **two mandatory kernel-mode round-trips per
throw**. 12 000 throws × 2 = 24 000 kernel transitions, combined with 4
096 synchronous `map->get()` server calls, made the loop slow enough for
the server-side connection health-check to fire and cancel the SQL
cursor (`Client cannot be reached`).
- Fix: fetch the first page before the main loop, run the three
`EXPECT_THROW` checks on its first row only, then iterate all pages in a
`for(;;)` loop starting from the already-fetched first page. Exception
count drops from **12 000 to 3**. The `bounds_checked` flag is
eliminated.

## Why it was Windows-only

Linux/macOS CI does not use ProcDump. Without a debugger attached,
`throw` → `catch` is entirely in-process with zero kernel transitions,
so the loop completes well within any timeout.

## Root cause detail

On Windows, C++ exceptions are built on SEH. When a debugger is attached
via `DebugActiveProcess()`, the kernel suspends the target process's
threads and delivers an `EXCEPTION_DEBUG_EVENT` to the debugger through
the kernel debug port. The debugger must call `WaitForDebugEvent()`,
process the event, and call `ContinueDebugEvent()` before the target
resumes. This happens for *every* throw, even ones that are immediately
caught — ProcDump cannot skip them. Under heavy exception load (12 000
throws), the cumulative stall is enough to trigger server-side timeouts.
…HZ-5459] (#1475)

Fixes #1474

### Problem

Since 5.7.0 a healthy C++ client connected to a multi-member cluster
continuously emits `WARNING` lines like:

```
Failed to set the response for invocation. Dropping the response. The state of the promise has already been set., ClientInvocation{ ... operation=map.put ... backup_acks_expected_ = 1, backup_acks_received = 1, ... }
```

A 10-client soak run produced 47,664 of these, all for backup-aware
operations with `backup_acks_expected == backup_acks_received`, with no
actual failures.

### Root cause

For a backup-aware operation the invocation completes once the primary
response and the backup ack(s) have arrived. Both `notify_response()`
and `notify_backup()` can win the final completion, and there is an
inherent race in which both reach `complete()` with the **same** pending
response:

1. `notify_response` stages `pending_response_`
2. `notify_backup` (other thread) increments the ack count and completes
the promise
3. `notify_response`'s recheck now sees `received == expected`, falls
through and calls `complete()` again →
`boost::promise_already_satisfied`

The future is completed exactly once with the correct value; the
duplicate is harmlessly dropped. Only the log line is wrong. The race
became routine after the multi-threaded pipeline work (#1412), which
made the response and the backup ack run on different threads.

This mirrors the Java client (`BaseInvocation.notifyResponse` has the
same double-check). The difference is reporting: Java's
`AbstractInvocationFuture.warnIfSuspiciousDoubleCompletion` only warns
when the already-set value differs from the offered one, so the
same-value backup-ack race is silent. The C++ `complete()` warned on
every `promise_already_satisfied`.

### Fix

`complete()` now mirrors Java: a duplicate completion with the same
response (the benign backup-ack race) is logged at `finest`, while a
genuinely conflicting value still warns. This also aligns the value path
with how `set_exception()` already handles the same condition.

### Tests

Added `client_invocation_test` with two cases driving the private
completion path via friend access:

- benign double completion with the same response → no `WARNING`, one
`finest`
- conflicting double completion with a different response → one
`WARNING`
@ihsandemir ihsandemir added this to the 5.7.0 milestone Jun 4, 2026
@dmitriyrazboev
dmitriyrazboev merged commit 6f86429 into 5.7.0 Jun 4, 2026
32 checks passed
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