Conversation
- Ensure Default Server Monitor calls close on resources before interrupt - Update ByteBufferBsonOutput documentation - Improve ReplyHeader testing and ensure resources are closed - Improve ServerSessionPool testing - Ensure reactive client session closing is idempotent - Added System.gc to unified test cleanup. Should cause more gc when testing. JAVA-6081
DefaultServerMonitor
Other changes
|
driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
Show resolved
Hide resolved
driver-sync/src/test/functional/com/mongodb/client/AbstractSessionsProseTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
This PR targets ByteBuf/leak-related issues by tightening resource lifecycle management in core/legacy/reactive code paths and by updating tests/docs to better enforce buffer ownership semantics.
Changes:
- Adjust server monitor and reactive session shutdown paths to close/cleanup resources more safely and make session close idempotent.
- Replace Spock specifications with JUnit 5 tests for
ServerSessionPoolandReplyHeader, and add new monitor edge-case tests. - Clarify/document ByteBuf ownership in
ByteBufferBsonOutputand add explicitByteBufreleasing in BSON serialization code.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java | Adds GC request during unified-test cleanup to help leak detection. |
| driver-sync/src/test/functional/com/mongodb/client/AbstractSessionsProseTest.java | Avoids assuming lsid exists in all commands during sessions prose tests. |
| driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/Fixture.java | Applies overridden TransportSettings to reactive-streams test client settings. |
| driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/ClientSessionPublisherImpl.java | Makes reactive client session closing idempotent and clears transaction context on close. |
| driver-legacy/src/main/com/mongodb/DBDecoderAdapter.java | Converts manual closes to try-with-resources for BSON writer/output. |
| driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolTest.java | New JUnit 5 tests replacing the removed Spock spec. |
| driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolSpecification.groovy | Removed Spock specification (replaced by JUnit 5 test). |
| driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorTest.java | Adds tests for close-during-open and null connection description scenarios. |
| driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java | New JUnit 5 tests replacing the removed Spock spec. |
| driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderSpecification.groovy | Removed Spock specification (replaced by JUnit 5 test). |
| driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java | Changes monitor shutdown/heartbeat flow to close connections under lock and handle null descriptions. |
| driver-core/src/main/com/mongodb/internal/connection/ByteBufferBsonOutput.java | Expands ByteBuf ownership documentation and uses ResourceUtil.release for safer cleanup. |
| config/spotbugs/exclude.xml | Adds a SpotBugs exclusion entry for DefaultServerMonitor. |
| bson/src/main/org/bson/BsonDocument.java | Explicitly releases ByteBufs during serialization proxy creation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolTest.java
Show resolved
Hide resolved
...streams/src/main/com/mongodb/reactivestreams/client/internal/ClientSessionPublisherImpl.java
Show resolved
Hide resolved
driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java
Show resolved
Hide resolved
driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorTest.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/internal/connection/ByteBufferBsonOutput.java
Show resolved
Hide resolved
driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
driver-core/src/test/functional/com/mongodb/internal/connection/ReplyHeaderTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorTest.java
Show resolved
Hide resolved
driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorTest.java
Outdated
Show resolved
Hide resolved
| List<ByteBuf> byteBuffers = buffer.getByteBuffers(); | ||
| for (ByteBuf cur : byteBuffers) { | ||
| System.arraycopy(cur.array(), cur.position(), bytes, curPos, cur.limit()); | ||
| curPos += cur.position(); |
There was a problem hiding this comment.
Calling cur.release() was also an option, right?
There was a problem hiding this comment.
Yeah it is, this follows the pattern used through out to clean up after the loop.
| return result; | ||
| }); | ||
|
|
||
| if (localConnection != null) { |
There was a problem hiding this comment.
Condition 'localConnection != null' is always 'true' ?
There was a problem hiding this comment.
If close was called twice it would be null on the second iteration
| return null; | ||
| }); | ||
| if (description != null) { | ||
| if (!shouldStreamResponses) { |
There was a problem hiding this comment.
Adding a sample should not be gated by description != null RTT sampling is independent of logging
| while (!isClosed) { | ||
| try { | ||
| if (connection == null) { | ||
| InternalConnection localConnection = connection; |
There was a problem hiding this comment.
Should we use withLock to dereference the connection?
| logStateChange(previousServerDescription, currentServerDescription); | ||
| sdamProvider.get().monitorUpdate(currentServerDescription); | ||
|
|
||
| InternalConnection localConnection = connection; |
There was a problem hiding this comment.
Connection accessed without the lock?
There was a problem hiding this comment.
So this use case is fine as its a single snapshot of a volatile here.
I double checked this with claude:
The simple snapshots (L228, L243, L260, L622, L646) are just a single volatile read followed by use of the local. They don't need atomicity with any other field — they just need to avoid reading connection twice. volatile alone is sufficient for that.
So the lock is needed reading a volatile field multiple times without atomicity. Between any two reads, close() or cancelCurrentCheck() on another thread can null the field, causing the second read to return null and NPE on the dereference.
eg Previous Code:
// This contains two read checks and the connection could be nulled inbetween.
if (connection == null || connection.isClosed()) {
// Do something
}
Fix for only do if not closed:
InternalConnection localConnection = withLock(lock, () -> {
if (connection == null || connection.isClosed()) {
return null;
}
return connection;
});
if (localConnection != null) {
// Do something
}
| logStateChange(previousServerDescription, currentServerDescription); | ||
| sdamProvider.get().monitorUpdate(currentServerDescription); | ||
|
|
||
| InternalConnection localConnection = connection; |
There was a problem hiding this comment.
So this use case is fine as its a single snapshot of a volatile here.
I double checked this with claude:
The simple snapshots (L228, L243, L260, L622, L646) are just a single volatile read followed by use of the local. They don't need atomicity with any other field — they just need to avoid reading connection twice. volatile alone is sufficient for that.
So the lock is needed reading a volatile field multiple times without atomicity. Between any two reads, close() or cancelCurrentCheck() on another thread can null the field, causing the second read to return null and NPE on the dereference.
eg Previous Code:
// This contains two read checks and the connection could be nulled inbetween.
if (connection == null || connection.isClosed()) {
// Do something
}
Fix for only do if not closed:
InternalConnection localConnection = withLock(lock, () -> {
if (connection == null || connection.isClosed()) {
return null;
}
return connection;
});
if (localConnection != null) {
// Do something
}
| return null; | ||
| }); | ||
| if (description != null) { | ||
| if (!shouldStreamResponses) { |
| while (!isClosed) { | ||
| try { | ||
| if (connection == null) { | ||
| InternalConnection localConnection = connection; |
JAVA-6081