Skip to content

Fix SqlTest.select Windows flake: move bounds-check EXPECT_THROWs outside the row loop [HZ-5424]#1471

Merged
ihsandemir merged 2 commits into
hazelcast:masterfrom
ihsandemir:fix/sqltest-select-windows-exception-overhead
Jun 2, 2026
Merged

Fix SqlTest.select Windows flake: move bounds-check EXPECT_THROWs outside the row loop [HZ-5424]#1471
ihsandemir merged 2 commits into
hazelcast:masterfrom
ihsandemir:fix/sqltest-select-windows-exception-overhead

Conversation

@ihsandemir

@ihsandemir ihsandemir commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

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, throwcatch 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.

Test plan

  • The three EXPECT_THROW boundary checks still execute (on the first row of the first page).
  • All 4 096 rows are still visited and verified through the restructured for(;;) loop.
  • CI build-pr Windows jobs pass without the SqlTest.select failure.

…side row loop

The test iterated over 4096 SQL rows and called EXPECT_THROW three times
per row to verify get_object() throws on an invalid index and unknown column
name.  That is ~12 000 C++ exception throws per test run.

On Windows the CI step attaches ProcDump as a debugger
  (procdump -e -ma -w client_test.exe).
Every C++ throw raises SEH code 0xE06D7363, which the OS delivers as a
first-chance debug event to ProcDump before the C++ catch handler can run.
ProcDump logs the line
  [HH:MM:SS]Exception: E06D7363.?AVindex_out_of_bounds@...
then calls ContinueDebugEvent() so execution can proceed -- two mandatory
kernel-mode transitions per throw.  12 000 throws * 2 = 24 000 kernel
round-trips, combined with 4096 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), failing the test.

Fix: fetch the first page before the loop and run the three EXPECT_THROW
checks on its first row only.  Exception count drops from 12 000 to 3.

Closes hazelcast#1470
@ihsandemir
ihsandemir force-pushed the fix/sqltest-select-windows-exception-overhead branch from fe69cdc to 6ca50e4 Compare June 2, 2026 06:38
@ihsandemir ihsandemir self-assigned this Jun 2, 2026
@ihsandemir
ihsandemir requested a review from JackPGreen June 2, 2026 06:39
@ihsandemir ihsandemir added this to the 5.7.0 milestone Jun 2, 2026
@ihsandemir ihsandemir changed the title Fix SqlTest.select Windows flake: move bounds-check EXPECT_THROWs outside the row loop Fix SqlTest.select Windows flake: move bounds-check EXPECT_THROWs outside the row loop [HZ-5424] Jun 2, 2026
Comment on lines +1873 to +1884
// Fetch the first page up front so we can verify the bounds-checking API
// on a single representative row before the main loop.
// Background: on Windows, C++ exceptions are built on SEH. When ProcDump
// is attached as a debugger (CI step: procdump -e -ma -w client_test.exe),
// every throw raises SEH code 0xE06D7363, which the OS delivers as a
// first-chance debug event to ProcDump before the C++ catch handler runs.
// ProcDump logs the line "[HH:MM:SS]Exception: E06D7363.?AV..." and then
// calls ContinueDebugEvent so execution can proceed. This is a mandatory
// two-kernel-mode-transition round-trip for every single throw.
// With the EXPECT_THROW calls inside the 4096-row loop that is ~12 000
// round-trips, stalling the loop long enough to trigger connection
// timeouts on the server side (Windows-only flaky failure).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit - this is very verbose and could probably be simplified.

@ihsandemir
ihsandemir enabled auto-merge (squash) June 2, 2026 08:54
@ihsandemir
ihsandemir merged commit 1732eed into hazelcast:master Jun 2, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SqlTest.select flakes on Windows: ~12 000 exception throws inside the row loop cause ProcDump debugger overhead → connection timeout [API-2383]

3 participants