diff --git a/org/postgresql/core/ConnectionFactory.java b/org/postgresql/core/ConnectionFactory.java index a351619..e2ba588 100644 --- a/org/postgresql/core/ConnectionFactory.java +++ b/org/postgresql/core/ConnectionFactory.java @@ -8,7 +8,10 @@ */ package org.postgresql.core; +import java.util.Collections; +import java.util.HashSet; import java.util.Properties; +import java.util.Set; import java.sql.SQLException; import org.postgresql.util.HostSpec; @@ -32,6 +35,11 @@ { "3", new org.postgresql.core.v3.ConnectionFactoryImpl() }, { "2", new org.postgresql.core.v2.ConnectionFactoryImpl() }, }; + + /** + * List of alive servers. + */ + private static final Set aliveServers = Collections.synchronizedSet(new HashSet()); /** * Establishes and initializes a new connection. @@ -54,6 +62,12 @@ public static ProtocolConnection openConnection(HostSpec[] hostSpecs, String user, String database, Properties info, Logger logger) throws SQLException { String protoName = info.getProperty("protocolVersion"); + // Adjust the order of hostSpecs to try the most suitable server first. + if(hostSpecs.length > 1) + { + hostSpecs = adjustHostSpecsOrder(hostSpecs); + } + for (int i = 0; i < versions.length; ++i) { String versionProtoName = (String) versions[i][0]; @@ -62,10 +76,30 @@ ConnectionFactory factory = (ConnectionFactory) versions[i][1]; ProtocolConnection connection = factory.openConnectionImpl(hostSpecs, user, database, info, logger); - if (connection != null) - return connection; + if (connection != null) { + if (hostSpecs.length > 1) { + String hostSpecKey = connection.getHostSpec().toString(); + + // Remove servers which can not be connected from the list of alive servers + for (int j = 0; j < hostSpecs.length; j++) { + if (hostSpecKey.equals(hostSpecs[j].toString())) + break; + + aliveServers.remove(hostSpecs[j].toString()); + } + // Add the current server to the list of alive servers + aliveServers.add(hostSpecKey); + } + return connection; + } } + if (hostSpecs.length > 1) { + // Remove servers which can not be connected from the list of alive servers + for (int j = 0; j < hostSpecs.length; j++) { + aliveServers.remove(hostSpecs[j].toString()); + } + } throw new PSQLException(GT.tr("A connection could not be made using the requested protocol {0}.", protoName), PSQLState.CONNECTION_UNABLE_TO_CONNECT); } @@ -86,4 +120,26 @@ * than protocol version incompatibility. */ public abstract ProtocolConnection openConnectionImpl(HostSpec[] hostSpecs, String user, String database, Properties info, Logger logger) throws SQLException; + + + /** + * Adjust the order of servers in hostSpecs, internally move first found alive server to head. + */ + private static HostSpec[] adjustHostSpecsOrder(HostSpec[] hostSpecs) { + if (aliveServers.isEmpty() + || aliveServers.contains(hostSpecs[0].toString())) + return hostSpecs; + + HostSpec[] result = hostSpecs.clone(); + + for (int i = 1; i < hostSpecs.length; i++) { + if (aliveServers.contains(hostSpecs[i].toString())) { + result[0] = hostSpecs[i]; + result[i] = hostSpecs[0]; + break; + } + } + + return result; + } }