diff --git a/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java b/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java index c713109ad..7b943ab61 100644 --- a/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java +++ b/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java @@ -783,4 +783,25 @@ public void rePrepareOnSlave(ServerPrepareResult oldServerPrepareResult, boolean oldServerPrepareResult.failover(serverPrepareResult.getStatementId(), secondaryProtocol); } } + + /** + * List current connected HostAddress. + * + * @return hostAddress List. + */ + public List connectedHosts() { + List usedHost = new ArrayList<>(); + + if (isMasterHostFail()) { + Protocol masterProtocol = waitNewMasterProtocol.get(); + if (masterProtocol != null) usedHost.add(masterProtocol.getHostAddress()); + } else usedHost.add(masterProtocol.getHostAddress()); + + if (isSecondaryHostFail()) { + Protocol secondProtocol = waitNewSecondaryProtocol.get(); + if (secondProtocol != null) usedHost.add(secondProtocol.getHostAddress()); + } else usedHost.add(secondaryProtocol.getHostAddress()); + + return usedHost; + } } diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AuroraProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AuroraProtocol.java index 1c1c82df9..16c8ca9bc 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AuroraProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AuroraProtocol.java @@ -62,8 +62,7 @@ import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayDeque; -import java.util.List; +import java.util.*; import java.util.concurrent.locks.ReentrantLock; import static org.mariadb.jdbc.internal.util.SqlStates.CONNECTION_EXCEPTION; @@ -117,7 +116,7 @@ public static void loop(AuroraListener listener, final List address throws SQLException { AuroraProtocol protocol; - ArrayDeque loopAddresses = new ArrayDeque<>((!addresses.isEmpty()) ? addresses : listener.getBlacklistKeys()); + Deque loopAddresses = new ArrayDeque<>((!addresses.isEmpty()) ? addresses : listener.getBlacklistKeys()); if (loopAddresses.isEmpty()) { loopAddresses.addAll(listener.getUrlParser().getHostAddresses()); } @@ -221,10 +220,10 @@ public static void loop(AuroraListener listener, final List address return; } - //loop is set so + // if server has try to connect to all host, and there is remaining master or slave that fail + // add all servers back to continue looping until maxConnectionTry is reached if (loopAddresses.isEmpty() && !searchFilter.isFailoverLoop() && maxConnectionTry > 0) { - //use blacklist if all server has been connected and no result - loopAddresses = new ArrayDeque<>(listener.getBlacklistKeys()); + resetHostList(listener, loopAddresses); } // Try to connect to the cluster if no other connection is good @@ -246,6 +245,33 @@ public static void loop(AuroraListener listener, final List address } } + /** + * Reinitialize loopAddresses with all hosts : all servers in randomize order with cluster address. + * If there is an active connection, connected host are remove from list. + * + * @param listener current listener + * @param loopAddresses the list to reinitialize + */ + private static void resetHostList(AuroraListener listener, Deque loopAddresses) { + //if all servers have been connected without result + //add back all servers + List servers = new ArrayList<>(); + servers.addAll(listener.getUrlParser().getHostAddresses()); + + Collections.shuffle(servers); + + //if cluster host is set, add it to the end of the list + if (listener.getClusterHostAddress() != null && listener.getUrlParser().getHostAddresses().size() < 2) { + servers.add(listener.getClusterHostAddress()); + } + + //remove current connected hosts to avoid reconnect them + servers.removeAll(listener.connectedHosts()); + + loopAddresses.clear(); + loopAddresses.addAll(loopAddresses); + } + /** * Initialize new protocol instance. * diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/MasterProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/MasterProtocol.java index 85de69e9e..ce53b5a1d 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/MasterProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/MasterProtocol.java @@ -60,8 +60,7 @@ import java.io.Closeable; import java.sql.SQLException; -import java.util.ArrayDeque; -import java.util.List; +import java.util.*; import java.util.concurrent.locks.ReentrantLock; @@ -138,9 +137,12 @@ public static void loop(Listener listener, final List addresses, lastQueryException = e; } + // if server has try to connect to all host, and master still fail + // add all servers back to continue looping until maxConnectionTry is reached if (loopAddresses.isEmpty() && !searchFilter.isFailoverLoop() && maxConnectionTry > 0) { - loopAddresses = new ArrayDeque<>(listener.getBlacklistKeys()); + resetHostList(listener, loopAddresses); } + } if (lastQueryException != null) { throw new SQLException("No active connection found for master : " + lastQueryException.getMessage(), @@ -149,4 +151,20 @@ public static void loop(Listener listener, final List addresses, throw new SQLException("No active connection found for master"); } + /** + * Reinitialize loopAddresses with all hosts : all servers in randomize order without connected host. + * + * @param listener current listener + * @param loopAddresses the list to reinitialize + */ + private static void resetHostList(Listener listener, Deque loopAddresses) { + //if all servers have been connected without result + //add back all servers + List servers = new ArrayList<>(); + servers.addAll(listener.getUrlParser().getHostAddresses()); + Collections.shuffle(servers); + + loopAddresses.clear(); + loopAddresses.addAll(loopAddresses); + } } diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/MastersSlavesProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/MastersSlavesProtocol.java index aa4c82e70..0bf363f04 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/MastersSlavesProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/MastersSlavesProtocol.java @@ -59,8 +59,7 @@ import org.mariadb.jdbc.internal.failover.tools.SearchFilter; import java.sql.SQLException; -import java.util.ArrayDeque; -import java.util.List; +import java.util.*; import java.util.concurrent.locks.ReentrantLock; public class MastersSlavesProtocol extends MasterProtocol { @@ -137,9 +136,10 @@ public static void loop(MastersSlavesListener listener, final List return; } - //loop is set so + // if server has try to connect to all host, and there is remaining master or slave that fail + // add all servers back to continue looping until maxConnectionTry is reached if (loopAddresses.isEmpty() && !searchFilter.isFailoverLoop() && maxConnectionTry > 0) { - loopAddresses = new ArrayDeque<>(listener.getBlacklistKeys()); + resetHostList(listener, loopAddresses); } } @@ -157,6 +157,26 @@ public static void loop(MastersSlavesListener listener, final List } + /** + * Reinitialize loopAddresses with all servers in randomize order. + * + * @param listener current listener + * @param loopAddresses the list to reinitialize + */ + private static void resetHostList(MastersSlavesListener listener, Deque loopAddresses) { + //if all servers have been connected without result + //add back all servers + List servers = new ArrayList<>(); + servers.addAll(listener.getUrlParser().getHostAddresses()); + Collections.shuffle(servers); + + //remove current connected hosts to avoid reconnect them + servers.removeAll(listener.connectedHosts()); + + loopAddresses.clear(); + loopAddresses.addAll(loopAddresses); + } + protected static boolean foundMaster(MastersSlavesListener listener, MastersSlavesProtocol protocol, SearchFilter searchFilter) { protocol.setMustBeMasterConnection(true);