Skip to content

Commit 11179a5

Browse files
authored
Hotfix 10.2.1 (#1830)
1 parent 468a35a commit 11179a5

File tree

12 files changed

+115
-227
lines changed

12 files changed

+115
-227
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.
33

44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
55

6+
## [10.2.1] HotFix & Stable Release
7+
### Fixed issues
8+
- Refactored Idle Connection Resiliency timeout to use existing SharedTimer [1794](https://github.com/microsoft/mssql-jdbc/pull/1794)
9+
- Fixed Managed Identity retry interval to exponential backoff properly [1770](https://github.com/microsoft/mssql-jdbc/pull/1770)
10+
- Removed extra call to executeCommand() within connectionCommand() [1754](https://github.com/microsoft/mssql-jdbc/pull/1754)
11+
612
## [10.2.0] Stable Release
713
### Added
814
- Support for datetimeoffset with sql_variant [1673](https://github.com/microsoft/mssql-jdbc/pull/1673)

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ We're now on the Maven Central Repository. Add the following to your POM file to
8080
<dependency>
8181
<groupId>com.microsoft.sqlserver</groupId>
8282
<artifactId>mssql-jdbc</artifactId>
83-
<version>10.2.0.jre17</version>
83+
<version>10.2.1.jre17</version>
8484
</dependency>
8585
```
8686
The driver can be downloaded from the [Microsoft Download Center](https://go.microsoft.com/fwlink/?linkid=2168495).
@@ -91,7 +91,7 @@ To get the latest preview version of the driver, add the following to your POM f
9191
<dependency>
9292
<groupId>com.microsoft.sqlserver</groupId>
9393
<artifactId>mssql-jdbc</artifactId>
94-
<version>10.2.0.jre17</version>
94+
<version>10.2.1.jre17</version>
9595
</dependency>
9696
```
9797

@@ -126,7 +126,7 @@ Projects that require either of the two features need to explicitly declare the
126126
<dependency>
127127
<groupId>com.microsoft.sqlserver</groupId>
128128
<artifactId>mssql-jdbc</artifactId>
129-
<version>10.2.0.jre17</version>
129+
<version>10.2.1.jre17</version>
130130
<scope>compile</scope>
131131
</dependency>
132132

@@ -144,7 +144,7 @@ Projects that require either of the two features need to explicitly declare the
144144
<dependency>
145145
<groupId>com.microsoft.sqlserver</groupId>
146146
<artifactId>mssql-jdbc</artifactId>
147-
<version>10.2.0.jre17</version>
147+
<version>10.2.1.jre17</version>
148148
<scope>compile</scope>
149149
</dependency>
150150

@@ -171,7 +171,7 @@ When setting 'useFmtOnly' property to 'true' for establishing a connection or cr
171171
<dependency>
172172
<groupId>com.microsoft.sqlserver</groupId>
173173
<artifactId>mssql-jdbc</artifactId>
174-
<version>10.2.0.jre17</version>
174+
<version>10.2.1.jre17</version>
175175
</dependency>
176176

177177
<dependency>

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
apply plugin: 'java'
1313

14-
version = '10.2.0'
14+
version = '10.2.1'
1515
def jreVersion = ""
1616
def testOutputDir = file("build/classes/java/test")
1717
def archivesBaseName = 'mssql-jdbc'

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.microsoft.sqlserver</groupId>
88
<artifactId>mssql-jdbc</artifactId>
9-
<version>10.2.0</version>
9+
<version>10.2.1</version>
1010
<packaging>jar</packaging>
1111

1212
<name>Microsoft JDBC Driver for SQL Server</name>

src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7531,43 +7531,6 @@ final void trySetSensitivityClassification(SensitivityClassification sensitivity
75317531
}
75327532

75337533

7534-
/**
7535-
* The tds default implementation of a timeout command
7536-
*/
7537-
class TdsTimeoutCommand extends TimeoutCommand<TDSCommand> {
7538-
protected TdsTimeoutCommand(int timeout, TDSCommand command, SQLServerConnection sqlServerConnection) {
7539-
super(timeout, command, sqlServerConnection);
7540-
}
7541-
7542-
protected void interrupt() throws Exception {
7543-
TDSCommand command = getCommand();
7544-
SQLServerConnection sqlServerConnection = getSqlServerConnection();
7545-
try {
7546-
// If TCP Connection to server is silently dropped, exceeding the query timeout
7547-
// on the same connection does
7548-
// not throw SQLTimeoutException
7549-
// The application stops responding instead until SocketTimeoutException is
7550-
// thrown. In this case, we must
7551-
// manually terminate the connection.
7552-
if (null == command && null != sqlServerConnection) {
7553-
sqlServerConnection.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED,
7554-
SQLServerException.getErrString("R_connectionIsClosed"));
7555-
} else {
7556-
// If the timer wasn't canceled before it ran out of
7557-
// time then interrupt the registered command.
7558-
if (null != command)
7559-
command.interrupt(SQLServerException.getErrString("R_queryTimedOut"));
7560-
}
7561-
} catch (SQLServerException e) {
7562-
// Request failed to time out and SQLServerConnection does not exist
7563-
if (null != command)
7564-
command.log(Level.FINE, "Command could not be timed out. Reason: " + e.getMessage());
7565-
throw new SQLServerException(SQLServerException.getErrString("R_crCommandCannotTimeOut"), e);
7566-
}
7567-
}
7568-
}
7569-
7570-
75717534
/**
75727535
* TDSCommand encapsulates an interruptable TDS conversation.
75737536
*
@@ -7695,13 +7658,7 @@ protected void setProcessedResponse(boolean processedResponse) {
76957658
private int queryTimeoutSeconds;
76967659
private int cancelQueryTimeoutSeconds;
76977660
private ScheduledFuture<?> timeout;
7698-
private TdsTimeoutCommand timeoutCommand;
76997661

7700-
/*
7701-
* Some flags for Connection Resiliency. We need to know if a command has already been registered in the poller, or
7702-
* if it was actually executed.
7703-
*/
7704-
private boolean isRegisteredInPoller = false;
77057662
private boolean isExecuted = false;
77067663

77077664
protected int getQueryTimeoutSeconds() {
@@ -7735,18 +7692,6 @@ void createCounter(ICounter previousCounter, Properties activeConnectionProperti
77357692
}
77367693
}
77377694

7738-
synchronized void addToPoller() {
7739-
if (!isRegisteredInPoller) {
7740-
// If command execution is subject to timeout then start timing until
7741-
// the server returns the first response packet.
7742-
if (queryTimeoutSeconds > 0) {
7743-
this.timeoutCommand = new TdsTimeoutCommand(queryTimeoutSeconds, this, null);
7744-
TimeoutPoller.getTimeoutPoller().addTimeoutCommand(this.timeoutCommand);
7745-
isRegisteredInPoller = true;
7746-
}
7747-
}
7748-
}
7749-
77507695
boolean wasExecuted() {
77517696
return isExecuted;
77527697
}
@@ -8162,7 +8107,6 @@ final TDSReader startResponse(boolean isAdaptive) throws SQLServerException {
81628107
SQLServerConnection conn = tdsReader != null ? tdsReader.getConnection() : null;
81638108
this.timeout = tdsWriter.getSharedTimer().schedule(new TDSTimeoutTask(this, conn), queryTimeoutSeconds);
81648109
}
8165-
addToPoller();
81668110

81678111
if (logger.isLoggable(Level.FINEST))
81688112
logger.finest(this.toString() + ": Reading response...");

src/main/java/com/microsoft/sqlserver/jdbc/IdleConnectionResiliency.java

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@
55

66
package com.microsoft.sqlserver.jdbc;
77

8+
import java.lang.Thread.State;
9+
import java.util.concurrent.ScheduledFuture;
810
import java.util.concurrent.atomic.AtomicInteger;
11+
import java.util.logging.Level;
912

1013

1114
class IdleConnectionResiliency {
15+
private static final java.util.logging.Logger loggerExternal = java.util.logging.Logger
16+
.getLogger("com.microsoft.sqlserver.jdbc.IdleConnectionResiliency");
1217
private boolean connectionRecoveryNegotiated;
1318
private int connectRetryCount;
1419
private SQLServerConnection connection;
1520
private SessionStateTable sessionStateTable;
1621
private ReconnectThread reconnectThread;
1722
private AtomicInteger unprocessedResponseCount = new AtomicInteger();
1823
private boolean connectionRecoveryPossible;
24+
private SQLServerException reconnectErrorReceived = null;
1925

2026
/*
2127
* Variables needed to perform a reconnect, these are not necessarily determined from just the connection string
@@ -27,7 +33,6 @@ class IdleConnectionResiliency {
2733

2834
IdleConnectionResiliency(SQLServerConnection connection) {
2935
this.connection = connection;
30-
reconnectThread = new ReconnectThread(connection);
3136
}
3237

3338
boolean isConnectionRecoveryNegotiated() {
@@ -54,8 +59,8 @@ void setConnection(SQLServerConnection connection) {
5459
this.connection = connection;
5560
}
5661

57-
ReconnectThread getReconnectThread() {
58-
return reconnectThread;
62+
boolean isReconnectRunning() {
63+
return reconnectThread != null && (reconnectThread.getState() != State.TERMINATED);
5964
}
6065

6166
SessionStateTable getSessionStateTable() {
@@ -105,24 +110,34 @@ void parseInitialSessionStateData(byte[] data, byte[][] sessionStateInitial) thr
105110
}
106111

107112
void incrementUnprocessedResponseCount() {
108-
if (connection.getRetryCount() > 0 && !getReconnectThread().isAlive()) {
109-
if (unprocessedResponseCount.incrementAndGet() < 0)
113+
if (connection.getRetryCount() > 0 && !isReconnectRunning()) {
114+
if (unprocessedResponseCount.incrementAndGet() < 0) {
110115
/*
111116
* When this number rolls over, connection recovery is disabled for the rest of the life of the
112117
* connection.
113118
*/
119+
if (loggerExternal.isLoggable(Level.FINER)) {
120+
loggerExternal.finer("unprocessedResponseCount < 0 on increment. Disabling connection resiliency.");
121+
}
122+
114123
setConnectionRecoveryPossible(false);
124+
}
115125
}
116126
}
117127

118128
void decrementUnprocessedResponseCount() {
119-
if (connection.getRetryCount() > 0 && !getReconnectThread().isAlive()) {
120-
if (unprocessedResponseCount.decrementAndGet() < 0)
129+
if (connection.getRetryCount() > 0 && !isReconnectRunning()) {
130+
if (unprocessedResponseCount.decrementAndGet() < 0) {
121131
/*
122132
* When this number rolls over, connection recovery is disabled for the rest of the life of the
123133
* connection.
124134
*/
135+
if (loggerExternal.isLoggable(Level.FINER)) {
136+
loggerExternal.finer("unprocessedResponseCount < 0 on decrement. Disabling connection resiliency.");
137+
}
138+
125139
setConnectionRecoveryPossible(false);
140+
}
126141
}
127142
}
128143

@@ -148,6 +163,20 @@ FailoverInfo getFailoverInfo() {
148163
int getLoginTimeoutSeconds() {
149164
return loginLoginTimeoutSeconds;
150165
}
166+
167+
void reconnect(TDSCommand cmd) throws InterruptedException {
168+
reconnectErrorReceived = null;
169+
reconnectThread = new ReconnectThread(this.connection, cmd);
170+
reconnectThread.start();
171+
reconnectThread.join();
172+
reconnectErrorReceived = reconnectThread.getException();
173+
// Remove reference so GC can clean it up
174+
reconnectThread = null;
175+
}
176+
177+
SQLServerException getReconnectException() {
178+
return reconnectErrorReceived;
179+
}
151180
}
152181

153182

@@ -370,6 +399,8 @@ public void reset() {
370399

371400

372401
final class ReconnectThread extends Thread {
402+
static final java.util.logging.Logger loggerExternal = java.util.logging.Logger
403+
.getLogger("com.microsoft.sqlserver.jdbc.ReconnectThread");
373404
private SQLServerConnection con = null;
374405
private SQLServerException eReceived = null;
375406
private TDSCommand command = null;
@@ -384,19 +415,23 @@ final class ReconnectThread extends Thread {
384415
@SuppressWarnings("unused")
385416
private ReconnectThread() {};
386417

387-
ReconnectThread(SQLServerConnection sqlC) {
418+
ReconnectThread(SQLServerConnection sqlC, TDSCommand cmd) {
388419
this.con = sqlC;
389-
}
390-
391-
// Resets the thread
392-
void init(TDSCommand cmd) {
393420
this.command = cmd;
394421
connectRetryCount = con.getRetryCount();
395422
eReceived = null;
396423
stopRequested = false;
424+
if (loggerExternal.isLoggable(Level.FINER)) {
425+
loggerExternal.finer("ReconnectThread initialized. Connection retry count = " + connectRetryCount
426+
+ "; Command = " + cmd.toString());
427+
}
428+
397429
}
398430

399431
public void run() {
432+
if (loggerExternal.isLoggable(Level.FINER)) {
433+
loggerExternal.finer("Starting ReconnectThread for command: " + command.toString());
434+
}
400435
boolean interruptsEnabled = command.getInterruptsEnabled();
401436
/*
402437
* All TDSCommands are not interruptible before execution, and all the commands passed to here won't have been
@@ -405,10 +440,24 @@ public void run() {
405440
*/
406441
command.setInterruptsEnabled(true);
407442
command.attachThread(this);
408-
command.addToPoller();
443+
444+
// We need a reference to the SharedTimer outside of the context of the connection
445+
SharedTimer timer = null;
446+
ScheduledFuture<?> timeout = null;
447+
448+
if (command.getQueryTimeoutSeconds() > 0) {
449+
timer = SharedTimer.getTimer();
450+
timeout = timer.schedule(new TDSTimeoutTask(command, null),
451+
command.getQueryTimeoutSeconds());
452+
}
453+
409454
boolean keepRetrying = true;
410455

411-
while ((connectRetryCount != 0) && (!stopRequested) && keepRetrying) {
456+
while ((connectRetryCount > 0) && (!stopRequested) && keepRetrying) {
457+
if (loggerExternal.isLoggable(Level.FINER)) {
458+
loggerExternal.finer("Running reconnect for command: " + command.toString() + " ; ConnectRetryCount = "
459+
+ connectRetryCount);
460+
}
412461
try {
413462
eReceived = null;
414463
con.connect(null, con.getPooledConnectionParent());
@@ -451,10 +500,26 @@ public void run() {
451500
}
452501

453502
command.setInterruptsEnabled(interruptsEnabled);
454-
return;
503+
504+
if (loggerExternal.isLoggable(Level.FINER)) {
505+
loggerExternal.finer("ReconnectThread exiting for command: " + command.toString());
506+
}
507+
508+
if (timeout != null) {
509+
timeout.cancel(false);
510+
timeout = null;
511+
}
512+
513+
if (timer != null) {
514+
timer.removeRef();
515+
timer = null;
516+
}
455517
}
456518

457519
void stop(boolean blocking) {
520+
if (loggerExternal.isLoggable(Level.FINER)) {
521+
loggerExternal.finer("ReconnectThread stop requested for command: " + command.toString());
522+
}
458523
stopRequested = true;
459524
if (blocking && this.isAlive()) {
460525
while (this.getState() != State.TERMINATED) {

src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
final class SQLJdbcVersion {
99
static final int major = 10;
1010
static final int minor = 2;
11-
static final int patch = 0;
11+
static final int patch = 1;
1212
static final int build = 0;
1313
/*
1414
* Used to load mssql-jdbc_auth DLL.

0 commit comments

Comments
 (0)