You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Normally we use the standard Statement.cancel() method to cancel running queries. If it's called on a connection made with multiSubnetFailover=true, it has no effect and both the original Thread executing the Statement and the Thread issuing the cancel() will hang until the statement completes.
This issue been tested and confirmed on the latest stable SQL Server JDBC driver as well as a number of older drivers (prior to the 6.x branch).
See below for a self-contained example of this. Replace the JDBC url with any recent version of SQL Server and flip the boolean multiSubnetFailover property between true/false to see the impact. The sample code issues a dummy WAITFOR statement to simulate a slow query and then tries to cancel it in a separate thread. If multiSubnetFailover is enabled, the cancellation never occurs as the canceler thread blocks waiting to write to the nio Channel (probably trying to write the ATTENTION cancellation packet).
Stepping through a debugger and comparing the stacks with multiSubnetFailover enabled/disabled, we noticed that the underlying SocketInputStream is a different class. When the feature is disabled, it's a java.net.SocketInputStream. When it's enabled it's a SocketAdaptor.SocketInputStream.
If I had to guess, I'd say that whatever the JDK is doing to spoof a Socket interface atop a Channel isn't as concurrent as a true Socket. It's a probably a shared lock acquired by a reader on the channel blocking the writer. These two lines look suspicious as they're both synchronizing on the same object:
While this could be a bug in the JDK, I'm not sure that non-blocking between readers/writers is part of the API contract for Sockets or at least Sockets derived from Channels. As such, this might be something you'd need to have the driver handle. The answer might be to switch to using real Sockets rather than Channels even when multiSubnetFailover is enabled.
Sample Program Reproduce Issue - QueryCancelTest.java
@sehrope thank you very much for filing this issue. We really appreciate the very detailed description and the sample code you gave. We will take a look and keep you updated. Thanks.
Normally we use the standard
Statement.cancel()
method to cancel running queries. If it's called on a connection made withmultiSubnetFailover=true
, it has no effect and both the original Thread executing theStatement
and the Thread issuing thecancel()
will hang until the statement completes.This issue been tested and confirmed on the latest stable SQL Server JDBC driver as well as a number of older drivers (prior to the 6.x branch).
See below for a self-contained example of this. Replace the JDBC url with any recent version of SQL Server and flip the boolean
multiSubnetFailover
property between true/false to see the impact. The sample code issues a dummyWAITFOR
statement to simulate a slow query and then tries to cancel it in a separate thread. IfmultiSubnetFailover
is enabled, the cancellation never occurs as the canceler thread blocks waiting to write to the nio Channel (probably trying to write the ATTENTION cancellation packet).Stack trace for thread:
stmt-canceller
Stack trace for thread:
main
Stepping through a debugger and comparing the stacks with
multiSubnetFailover
enabled/disabled, we noticed that the underlyingSocketInputStream
is a different class. When the feature is disabled, it's ajava.net.SocketInputStream
. When it's enabled it's aSocketAdaptor.SocketInputStream
.If I had to guess, I'd say that whatever the JDK is doing to spoof a Socket interface atop a Channel isn't as concurrent as a true Socket. It's a probably a shared lock acquired by a reader on the channel blocking the writer. These two lines look suspicious as they're both synchronizing on the same object:
https://github.com/openjdk-mirror/jdk/blob/jdk8u/jdk8u/master/src/share/classes/sun/nio/ch/SocketAdaptor.java#L188
https://github.com/openjdk-mirror/jdk/blob/jdk8u/jdk8u/master/src/share/classes/java/nio/channels/Channels.java#L95
While this could be a bug in the JDK, I'm not sure that non-blocking between readers/writers is part of the API contract for Sockets or at least Sockets derived from Channels. As such, this might be something you'd need to have the driver handle. The answer might be to switch to using real Sockets rather than Channels even when multiSubnetFailover is enabled.
Sample Program Reproduce Issue -
QueryCancelTest.java
The text was updated successfully, but these errors were encountered: