Skip to content

Commit 53e6875

Browse files
committed
Fix for Bug#23143279, CLIENT HANG WHEN LOADBALANCESTRATEGY IS BESTRESPONSETIME.
Change-Id: I5a72e15d4f6647c18c1a407347014be75199554f
1 parent 2c79721 commit 53e6875

File tree

3 files changed

+122
-9
lines changed

3 files changed

+122
-9
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Version 8.4.0
55

6+
- Fix for Bug#23143279, CLIENT HANG WHEN LOADBALANCESTRATEGY IS BESTRESPONSETIME.
7+
68
Version 8.3.0
79

810
- Fix for Bug#107107 (Bug#34101635), Redundant "Reset stmt" when setting useServerPrepStmts&cachePrepStmts to true.

src/main/user-impl/java/com/mysql/cj/jdbc/ha/BestResponseTimeBalanceStrategy.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2023, Oracle and/or its affiliates.
2+
* Copyright (c) 2002, 2024, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -31,6 +31,7 @@
3131

3232
import java.lang.reflect.InvocationHandler;
3333
import java.sql.SQLException;
34+
import java.util.ArrayList;
3435
import java.util.List;
3536
import java.util.Map;
3637

@@ -45,13 +46,14 @@ public BestResponseTimeBalanceStrategy() {
4546
@Override
4647
public ConnectionImpl pickConnection(InvocationHandler proxy, List<String> configuredHosts, Map<String, JdbcConnection> liveConnections,
4748
long[] responseTimes, int numRetries) throws SQLException {
49+
List<String> allowList = new ArrayList<>(configuredHosts.size());
50+
allowList.addAll(configuredHosts);
4851
Map<String, Long> blockList = ((LoadBalancedConnectionProxy) proxy).getGlobalBlocklist();
52+
allowList.removeAll(blockList.keySet());
4953

5054
SQLException ex = null;
51-
5255
for (int attempts = 0; attempts < numRetries;) {
5356
long minResponseTime = Long.MAX_VALUE;
54-
5557
int bestHostIndex = 0;
5658

5759
// safety
@@ -62,10 +64,9 @@ public ConnectionImpl pickConnection(InvocationHandler proxy, List<String> confi
6264
for (int i = 0; i < responseTimes.length; i++) {
6365
long candidateResponseTime = responseTimes[i];
6466

65-
if (candidateResponseTime < minResponseTime && !blockList.containsKey(configuredHosts.get(i))) {
67+
if (candidateResponseTime < minResponseTime && !blockList.containsKey(allowList.get(i))) {
6668
if (candidateResponseTime == 0) {
6769
bestHostIndex = i;
68-
6970
break;
7071
}
7172

@@ -74,10 +75,8 @@ public ConnectionImpl pickConnection(InvocationHandler proxy, List<String> confi
7475
}
7576
}
7677

77-
String bestHost = configuredHosts.get(bestHostIndex);
78-
78+
String bestHost = allowList.get(bestHostIndex);
7979
ConnectionImpl conn = (ConnectionImpl) liveConnections.get(bestHost);
80-
8180
if (conn == null) {
8281
try {
8382
conn = ((LoadBalancedConnectionProxy) proxy).createConnectionForHost(bestHost);

src/test/java/testsuite/regression/ConnectionRegressionTest.java

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2023, Oracle and/or its affiliates.
2+
* Copyright (c) 2002, 2024, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -12017,4 +12017,116 @@ public void handleSessionStateChanges(ServerSessionStateChanges changes) {
1201712017

1201812018
}
1201912019

12020+
/**
12021+
* Test fix for Bug#23143279, CLIENT HANG WHEN LOADBALANCESTRATEGY IS BESTRESPONSETIME.
12022+
*
12023+
* @throws Exception
12024+
*/
12025+
@Test
12026+
public void testBug23143279() throws Exception {
12027+
testBug23143279RunTest("random");
12028+
testBug23143279RunTest("bestResponseTime");
12029+
testBug23143279RunTest("serverAffinity");
12030+
testBug23143279RunTest(SequentialBalanceStrategy.class.getName());
12031+
}
12032+
12033+
private void testBug23143279RunTest(String lbStrategy) throws Exception {
12034+
final String defaultHost = getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.HOST.getKeyName());
12035+
final String defaultPort = getPropertiesFromTestsuiteUrl().getProperty(PropertyKey.PORT.getKeyName());
12036+
12037+
final String host1 = "first";
12038+
final String host2 = "second";
12039+
final String host3 = "third";
12040+
final String host4 = "fourth";
12041+
final String hostPort4 = host4 + ":" + defaultPort;
12042+
12043+
final String uniqueId = String.valueOf(lbStrategy.substring(lbStrategy.lastIndexOf('.') + 1, lbStrategy.lastIndexOf('.') + 4)).toUpperCase();
12044+
final String connGroupName = "testBug23143279" + uniqueId;
12045+
12046+
final Properties props = new Properties();
12047+
props.setProperty(PropertyKey.sslMode.getKeyName(), "DISABLED");
12048+
props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "0");
12049+
props.setProperty(PropertyKey.loadBalanceConnectionGroup.getKeyName(), connGroupName);
12050+
props.setProperty(PropertyKey.ha_loadBalanceStrategy.getKeyName(), lbStrategy);
12051+
12052+
System.out.println("\n\nTEST: " + lbStrategy);
12053+
System.out.println("********************************************************************************");
12054+
System.out.println("\tHosts group: " + connGroupName);
12055+
12056+
final Connection testConn = getUnreliableLoadBalancedConnection(new String[] { host1, host2, host3 }, props,
12057+
new HashSet<>(Arrays.asList(host2, host3)));
12058+
UnreliableSocketFactory.mapHost(host4, defaultHost);
12059+
12060+
System.out.println("\nStep 1: initial connection");
12061+
System.out.println("********************************************************************************");
12062+
System.out.println("\tHosts count: " + ConnectionGroupManager.getActiveHostCount(connGroupName));
12063+
System.out.println("\tHosts: " + ConnectionGroupManager.getActiveHostLists(connGroupName));
12064+
System.out.println("\tConnected to: " + ((JdbcConnection) testConn).getHostPortPair());
12065+
System.out.println("\tConnection id: " + ((MysqlConnection) testConn).getId());
12066+
12067+
assertEquals(host1 + ":" + defaultPort, ((JdbcConnection) testConn).getHostPortPair());
12068+
12069+
this.stmt.execute("KILL CONNECTION " + ((MysqlConnection) testConn).getId());
12070+
assertThrows(SQLException.class, () -> testConn.createStatement().executeQuery("SELECT 1"));
12071+
12072+
System.out.println("\nStep 2: after killing the active connection and having reconnected");
12073+
System.out.println("********************************************************************************");
12074+
System.out.println("\tHosts count: " + ConnectionGroupManager.getActiveHostCount(connGroupName));
12075+
System.out.println("\tHosts: " + ConnectionGroupManager.getActiveHostLists(connGroupName));
12076+
System.out.println("\tConnected to: " + ((JdbcConnection) testConn).getHostPortPair());
12077+
System.out.println("\tConnection id: " + ((MysqlConnection) testConn).getId());
12078+
12079+
assertEquals(host1 + ":" + defaultPort, ((JdbcConnection) testConn).getHostPortPair());
12080+
12081+
ConnectionGroupManager.addHost(connGroupName, hostPort4, true);
12082+
12083+
System.out.println("\nStep 3: after adding a new host");
12084+
System.out.println("********************************************************************************");
12085+
System.out.println("\tHosts count: " + ConnectionGroupManager.getActiveHostCount(connGroupName));
12086+
System.out.println("\tHosts: " + ConnectionGroupManager.getActiveHostLists(connGroupName));
12087+
System.out.println("\tConnected to: " + ((JdbcConnection) testConn).getHostPortPair());
12088+
System.out.println("\tConnection id: " + ((MysqlConnection) testConn).getId());
12089+
12090+
this.stmt.execute("KILL CONNECTION " + ((MysqlConnection) testConn).getId());
12091+
assertThrows(SQLException.class, () -> testConn.createStatement().executeQuery("SELECT 1"));
12092+
// Should be reconnected by now.
12093+
12094+
boolean connectedToHost1 = ((JdbcConnection) testConn).getHostPortPair().startsWith(host1);
12095+
assertEquals((connectedToHost1 ? host1 : host4) + ":" + defaultPort, ((JdbcConnection) testConn).getHostPortPair());
12096+
12097+
System.out.println("\nStep 4: after killing the active connection and having reconnected");
12098+
System.out.println("********************************************************************************");
12099+
System.out.println("\tHosts count: " + ConnectionGroupManager.getActiveHostCount(connGroupName));
12100+
System.out.println("\tHosts: " + ConnectionGroupManager.getActiveHostLists(connGroupName));
12101+
System.out.println("\tConnected to: " + ((JdbcConnection) testConn).getHostPortPair());
12102+
System.out.println("\tConnection id: " + ((MysqlConnection) testConn).getId());
12103+
12104+
final String hostToRemove = ((JdbcConnection) testConn).getHostPortPair();
12105+
ExecutorService executor = Executors.newSingleThreadExecutor();
12106+
Future<?> future = executor.submit(() -> {
12107+
ConnectionGroupManager.removeHost(connGroupName, hostToRemove, true);
12108+
return null;
12109+
});
12110+
12111+
try {
12112+
future.get(10, TimeUnit.SECONDS);
12113+
} catch (TimeoutException e) {
12114+
executor.shutdownNow();
12115+
fail("Failed to remove host and connect to a new one.\n"
12116+
+ "WARNING: A ConcurrentModificationException on UnreliableSocketFactory can happen from now on.");
12117+
}
12118+
executor.shutdownNow();
12119+
12120+
System.out.println("\nStep 5: after removing the connected host [" + hostToRemove + "]");
12121+
System.out.println("********************************************************************************");
12122+
System.out.println("\tHosts count: " + ConnectionGroupManager.getActiveHostCount(connGroupName));
12123+
System.out.println("\tHosts: " + ConnectionGroupManager.getActiveHostLists(connGroupName));
12124+
System.out.println("\tConnected to: " + ((JdbcConnection) testConn).getHostPortPair());
12125+
System.out.println("\tConnection id: " + ((MysqlConnection) testConn).getId());
12126+
12127+
assertEquals((connectedToHost1 ? host4 : host1) + ":" + defaultPort, ((JdbcConnection) testConn).getHostPortPair());
12128+
12129+
testConn.close();
12130+
}
12131+
1202012132
}

0 commit comments

Comments
 (0)