ARTEMIS-6142 Ensure InVM connections are removed on graceful close#6566
Open
MrEasy wants to merge 1 commit into
Open
ARTEMIS-6142 Ensure InVM connections are removed on graceful close#6566MrEasy wants to merge 1 commit into
MrEasy wants to merge 1 commit into
Conversation
Two defects could cause RemotingServiceImpl.removeConnection to be skipped even though ActiveMQConnection.close() was called over the InVM transport, leaking the server-side connection permanently (InVM connection-ttl is -1, so the failure-check reaper never removes it): 1. InVMAcceptor/InVMConnector reported every close - including a graceful close() - to the peer as a failure (disconnect()), routing it through issueFailure() with a RemoteDisconnectException instead of issueClose(). The graceful/failure flag is now propagated so a graceful close stays graceful, matching Netty semantics. 2. issueClose() gated removal on !isSupportReconnect(). A graceful close is an explicit teardown and must always remove the connection; reconnect/reattach support must not keep a gracefully closed connection lingering. The guard is removed for the graceful-close path. Adds InVMConnectionLeakStressTest, a concurrent flood of reconnect-capable (confirmation-window enabled) connections that widens the timing window in which the leak occurs. Fix race condition in InVMConnection - closed is now volatile (it's also read unsynchronized from the write executor at line 218). - internalClose is now fully atomic: the closed check, the connectionDestroyed callback, and the closing/closed state transitions all happen inside a single synchronized (this) block. The previous lock-free if (closing) return; fast path was removed. Why this matters: The exactly-once firing already held in the old code, so that alone wasn't the bug. The real latent defect was a premature return: the lock-free fast path let a losing concurrent caller's close()/disconnect() return before the winning thread had actually fired connectionDestroyed. Callers could then proceed believing the connection was fully torn down while the destroy callback (and thus the downstream RemotingServiceImpl.removeConnection chain) hadn't run yet. Now every caller blocks on the monitor until the destroy callback has completed. Test — InVMConnectionTest.java - Added testConcurrentCloseFiresConnectionDestroyedExactlyOnce: 16 threads aligned on a CyclicBarrier all call close()/disconnect() at once, over 50 rounds. The listener sleeps briefly inside connectionDestroyed to widen the race window. Each worker asserts, right after its call returns, that the destroy has already fired. - Asserts both exactly-once firing and zero premature returns.
jbertram
requested changes
Jul 7, 2026
| } | ||
|
|
||
| closing = true; | ||
| closing = true; |
Contributor
There was a problem hiding this comment.
The closing field can be removed completely.
Contributor
|
Overall this looks good. However, the comments and the commit message are extremely wordy (something I've noticed with LLMs). Also, there is significant overlap between the code comments and the commit message. The commit message should give a clear, concise overview of the change, and details about particular bits of code should be in the source. There should be minimal overlap between the two. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two defects could cause RemotingServiceImpl.removeConnection to be skipped even though ActiveMQConnection.close() was called over the InVM transport, leaking the server-side connection permanently (InVM connection-ttl is -1, so the failure-check reaper never removes it):
InVMAcceptor/InVMConnector reported every close - including a graceful close() - to the peer as a failure (disconnect()), routing it through issueFailure() with a RemoteDisconnectException instead of issueClose(). The graceful/failure flag is now propagated so a graceful close stays graceful, matching Netty semantics.
issueClose() gated removal on !isSupportReconnect(). A graceful close is an explicit teardown and must always remove the connection; reconnect/reattach support must not keep a gracefully closed connection lingering. The guard is removed for the graceful-close path.
Adds InVMConnectionLeakStressTest, a concurrent flood of reconnect-capable (confirmation-window enabled) connections that widens the timing window in which the leak occurs.
Fix race condition in InVMConnection