Skip to content

Commit e4095e2

Browse files
authored
Merge pull request microsoft#162 from v-xiangs/ExecutorService-instead-of-Thread
Executor service instead of thread
2 parents a53054d + a9d41cc commit e4095e2

File tree

3 files changed

+144
-8
lines changed

3 files changed

+144
-8
lines changed

pom.xml

+14-2
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,27 @@
114114
<artifactId>junit-jupiter-engine</artifactId>
115115
<version>5.0.0-M3</version>
116116
<scope>test</scope>
117-
</dependency>
117+
</dependency>
118+
<dependency>
119+
<groupId>com.zaxxer</groupId>
120+
<artifactId>HikariCP</artifactId>
121+
<version>2.6.0</version>
122+
<scope>test</scope>
123+
</dependency>
124+
<dependency>
125+
<groupId>org.apache.commons</groupId>
126+
<artifactId>commons-dbcp2 </artifactId>
127+
<version>2.1.1</version>
128+
<scope>test</scope>
129+
</dependency>
118130
<!--
119131
<dependency>
120132
<groupId>org.junit.vintage</groupId>
121133
<artifactId>junit-vintage-engine</artifactId>
122134
<version>4.12.0-M3</version>
123135
<scope>test</scope>
124136
</dependency>
125-
-->
137+
-->
126138
</dependencies>
127139

128140
<profiles>

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

+22-6
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@
5555
import java.util.Set;
5656
import java.util.SimpleTimeZone;
5757
import java.util.TimeZone;
58+
import java.util.concurrent.ExecutorService;
59+
import java.util.concurrent.Executors;
60+
import java.util.concurrent.Future;
5861
import java.util.concurrent.SynchronousQueue;
62+
import java.util.concurrent.ThreadFactory;
5963
import java.util.concurrent.ThreadPoolExecutor;
6064
import java.util.concurrent.TimeUnit;
6165
import java.util.concurrent.atomic.AtomicInteger;
@@ -6827,9 +6831,23 @@ final void TryProcessFeatureExtAck(boolean featureExtAckReceived) throws SQLServ
68276831
* a reason like "timed out".
68286832
*/
68296833
final class TimeoutTimer implements Runnable {
6834+
private static final String threadGroupName = "mssql-jdbc-TimeoutTimer";
68306835
private final int timeoutSeconds;
68316836
private final TDSCommand command;
6832-
private Thread timerThread;
6837+
private volatile Future<?> task;
6838+
6839+
private static final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
6840+
private final ThreadGroup tg = new ThreadGroup(threadGroupName);
6841+
private final String threadNamePrefix = tg.getName() + "-";
6842+
private final AtomicInteger threadNumber = new AtomicInteger(0);
6843+
@Override
6844+
public Thread newThread(Runnable r) {
6845+
Thread t = new Thread(tg, r, threadNamePrefix + threadNumber.incrementAndGet());
6846+
t.setDaemon(true);
6847+
return t;
6848+
}
6849+
});
6850+
68336851
private volatile boolean canceled = false;
68346852

68356853
TimeoutTimer(int timeoutSeconds,
@@ -6842,17 +6860,15 @@ final class TimeoutTimer implements Runnable {
68426860
}
68436861

68446862
final void start() {
6845-
timerThread = new Thread(this);
6846-
timerThread.setDaemon(true);
6847-
timerThread.start();
6863+
task = executor.submit(this);
68486864
}
68496865

68506866
final void stop() {
6867+
task.cancel(true);
68516868
canceled = true;
6852-
timerThread.interrupt();
68536869
}
68546870

6855-
public void run() {
6871+
public void run() {
68566872
int secondsRemaining = timeoutSeconds;
68576873
try {
68586874
// Poll every second while time is left on the timer.

src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java

+108
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,20 @@
1111
import static org.junit.jupiter.api.Assertions.assertTrue;
1212
import static org.junit.jupiter.api.Assumptions.assumeTrue;
1313

14+
import java.lang.management.ManagementFactory;
15+
import java.lang.management.ThreadInfo;
1416
import java.sql.Connection;
1517
import java.sql.DriverManager;
18+
import java.sql.PreparedStatement;
19+
import java.sql.ResultSet;
1620
import java.sql.SQLException;
1721
import java.sql.Statement;
1822
import java.util.UUID;
1923

24+
import javax.sql.DataSource;
2025
import javax.sql.PooledConnection;
2126

27+
import org.apache.commons.dbcp2.BasicDataSource;
2228
import org.junit.jupiter.api.Test;
2329
import org.junit.platform.runner.JUnitPlatform;
2430
import org.junit.runner.RunWith;
@@ -30,7 +36,13 @@
3036
import com.microsoft.sqlserver.testframework.DBConnection;
3137
import com.microsoft.sqlserver.testframework.DBTable;
3238
import com.microsoft.sqlserver.testframework.util.RandomUtil;
39+
import com.zaxxer.hikari.HikariConfig;
40+
import com.zaxxer.hikari.HikariDataSource;
3341

42+
/**
43+
* Tests pooled connection
44+
*
45+
*/
3446
@RunWith(JUnitPlatform.class)
3547
public class PoolingTest extends AbstractTest {
3648
@Test
@@ -139,4 +151,100 @@ public void testConnectionPoolClientConnectionId() throws SQLException {
139151

140152
assertEquals(Id1, Id2, "ClientConnection Ids from pool are not the same.");
141153
}
154+
155+
/**
156+
* test connection pool with HikariCP
157+
*
158+
* @throws SQLException
159+
*/
160+
@Test
161+
public void testHikariCP() throws SQLException {
162+
HikariConfig config = new HikariConfig();
163+
config.setJdbcUrl(connectionString);
164+
HikariDataSource ds = new HikariDataSource(config);
165+
166+
try{
167+
connect(ds);
168+
}
169+
finally{
170+
ds.close();
171+
}
172+
}
173+
174+
/**
175+
* test connection pool with Apache DBCP
176+
*
177+
* @throws SQLException
178+
*/
179+
@Test
180+
public void testApacheDBCP() throws SQLException {
181+
BasicDataSource ds = new BasicDataSource();
182+
ds.setUrl(connectionString);
183+
184+
try{
185+
connect(ds);
186+
}
187+
finally{
188+
ds.close();
189+
}
190+
}
191+
192+
193+
/**
194+
* setup connection, get connection from pool, and test threads
195+
*
196+
* @param ds
197+
* @throws SQLException
198+
*/
199+
private static void connect(DataSource ds) throws SQLException {
200+
Connection con = null;
201+
PreparedStatement pst = null;
202+
ResultSet rs = null;
203+
204+
try {
205+
con = ds.getConnection();
206+
pst = con.prepareStatement("SELECT SUSER_SNAME()");
207+
pst.setQueryTimeout(5);
208+
rs = pst.executeQuery();
209+
210+
assertTrue(countTimeoutThreads() >= 1, "Timeout timer is missing.");
211+
212+
while (rs.next()) {
213+
rs.getString(1);
214+
}
215+
}
216+
finally {
217+
if (rs != null) {
218+
rs.close();
219+
}
220+
221+
if (pst != null) {
222+
pst.close();
223+
}
224+
225+
if (con != null) {
226+
con.close();
227+
}
228+
}
229+
}
230+
231+
/**
232+
* count number of mssql-jdbc-TimeoutTimer threads
233+
*
234+
* @return
235+
*/
236+
private static int countTimeoutThreads() {
237+
int count = 0;
238+
String threadName = "mssql-jdbc-TimeoutTimer";
239+
240+
ThreadInfo[] tinfos = ManagementFactory.getThreadMXBean().getThreadInfo(ManagementFactory.getThreadMXBean().getAllThreadIds(), 0);
241+
242+
for (ThreadInfo ti : tinfos) {
243+
if ((ti.getThreadName().startsWith(threadName)) && (ti.getThreadState().equals(java.lang.Thread.State.TIMED_WAITING))) {
244+
count++;
245+
}
246+
}
247+
248+
return count;
249+
}
142250
}

0 commit comments

Comments
 (0)