765 Todd Farmer 2009-03-06
BUG#43421 - Made doPing() global blacklist-aware, so that it does not throw
Exceptions when at least a single load-balanced server is available.
modified:
CHANGES
src/com/mysql/jdbc/LoadBalancingConnectionProxy.java
src/testsuite/UnreliableSocketFactory.java
src/testsuite/regression/ConnectionRegressionTest.java
764 markm@stripped 2009-03-05
Added a version check around getting the variable 'auto_increment_increment' for
servers < 5.0.2, which quiets down a warning message that the driver would
log
when connecting to MySQL-4.1 or older.
modified:
CHANGES
src/com/mysql/jdbc/ConnectionImpl.java
=== modified file 'CHANGES'
--- a/CHANGES 2009-03-06 04:15:44 +0000
+++ b/CHANGES 2009-03-06 21:56:57 +0000
@@ -1,6 +1,9 @@
# Changelog
# $Id$
nn-nn-08 - Version 5.1.8
+ - Fixed BUG#43421 - Made doPing() global blacklist-aware, so that it does not
+ throw Exceptions when at least a single load-balanced server is available.
+
- Fixed BUG#43071 - Specifying ASCII encoding for converting seed String to
byte array; allowing system default encoding to be used causes auth failures
on EBCDIC platforms.
=== modified file 'src/com/mysql/jdbc/LoadBalancingConnectionProxy.java'
--- a/src/com/mysql/jdbc/LoadBalancingConnectionProxy.java 2009-01-13 23:55:53 +0000
+++ b/src/com/mysql/jdbc/LoadBalancingConnectionProxy.java 2009-03-06 21:56:57 +0000
@@ -318,7 +318,7 @@ public class LoadBalancingConnectionProx
}
if ("close".equals(methodName)) {
- synchronized (this.liveConnections) {
+ synchronized (this) {
// close all underlying connections
Iterator allConnections = this.liveConnections.values()
.iterator();
@@ -473,11 +473,35 @@ public class LoadBalancingConnectionProx
}
public synchronized void doPing() throws SQLException {
- Iterator allConns = this.liveConnections.values().iterator();
-
- while (allConns.hasNext()) {
- ((Connection)allConns.next()).ping();
+ if(this.isGlobalBlacklistEnabled()){
+ SQLException se = null;
+ boolean foundHost = false;
+ synchronized(this){
+ for(Iterator i = this.hostList.iterator(); i.hasNext(); ){
+ String host = (String) i.next();
+ Connection conn = (Connection) this.liveConnections.get(host);
+ if(conn == null){
+ continue;
+ }
+ try{
+ conn.ping();
+ foundHost = true;
+ } catch (SQLException e){
+ se = e;
+ this.addToGlobalBlacklist(host);
+ }
+ }
+ }
+ if(!foundHost){
+ throw se;
+ }
+ } else {
+ Iterator allConns = this.liveConnections.values().iterator();
+ while (allConns.hasNext()) {
+ ((Connection)allConns.next()).ping();
+ }
}
+
}
public void addToGlobalBlacklist(String host) {
=== modified file 'src/testsuite/UnreliableSocketFactory.java'
--- a/src/testsuite/UnreliableSocketFactory.java 2008-10-20 22:29:45 +0000
+++ b/src/testsuite/UnreliableSocketFactory.java 2009-03-06 21:56:57 +0000
@@ -63,6 +63,18 @@ public class UnreliableSocketFactory ext
static final Set IMMEDIATELY_DOWNED_HOSTS = new HashSet();
+ private String hostname;
+ private int portNumber;
+ private Properties props;
+
+ public static void flushAllHostLists(){
+ IMMEDIATELY_DOWNED_HOSTS.clear();
+ HUNG_CONNECT_HOSTS.clear();
+ HUNG_READ_HOSTS.clear();
+ HUNG_WRITE_HOSTS.clear();
+ }
+
+
public static void mapHost(String alias, String orig) {
MAPPED_HOSTS.put(alias, orig);
}
@@ -102,6 +114,13 @@ public class UnreliableSocketFactory ext
public Socket connect(String hostname, int portNumber, Properties props)
throws SocketException, IOException {
+ this.hostname = hostname;
+ this.portNumber = portNumber;
+ this.props = props;
+ return getNewSocket();
+ }
+
+ private Socket getNewSocket() throws SocketException, IOException {
if (IMMEDIATELY_DOWNED_HOSTS.contains(hostname)) {
sleepMillisForProperty(props, "connectTimeout");
@@ -117,6 +136,16 @@ public class UnreliableSocketFactory ext
return new HangingSocket(super.connect(hostnameToConnectTo, portNumber, props), props,
hostname);
}
+
+
+
+ public Socket afterHandshake() throws SocketException, IOException {
+ return getNewSocket();
+ }
+
+ public Socket beforeHandshake() throws SocketException, IOException {
+ return getNewSocket();
+ }
static void sleepMillisForProperty(Properties props, String name) {
try {
@@ -364,7 +393,7 @@ public class UnreliableSocketFactory ext
}
private void failIfRequired() throws SocketTimeoutException {
- if (HUNG_READ_HOSTS.contains(aliasedHostname)) {
+ if (HUNG_READ_HOSTS.contains(aliasedHostname) ||
IMMEDIATELY_DOWNED_HOSTS.contains(aliasedHostname)) {
sleepMillisForProperty(props, "socketTimeout");
throw new SocketTimeoutException();
@@ -416,7 +445,7 @@ public class UnreliableSocketFactory ext
}
private void failIfRequired() throws SocketTimeoutException {
- if (HUNG_WRITE_HOSTS.contains(aliasedHostname)) {
+ if (HUNG_WRITE_HOSTS.contains(aliasedHostname) ||
IMMEDIATELY_DOWNED_HOSTS.contains(aliasedHostname)) {
sleepMillisForProperty(props, "socketTimeout");
throw new SocketTimeoutException();
=== modified file 'src/testsuite/regression/ConnectionRegressionTest.java'
--- a/src/testsuite/regression/ConnectionRegressionTest.java 2008-10-20 22:29:45 +0000
+++ b/src/testsuite/regression/ConnectionRegressionTest.java 2009-03-06 21:56:57 +0000
@@ -44,6 +44,7 @@ import java.util.Properties;
import java.util.StringTokenizer;
import testsuite.BaseTestCase;
+import testsuite.UnreliableSocketFactory;
import com.mysql.jdbc.ConnectionImpl;
import com.mysql.jdbc.Driver;
@@ -2437,4 +2438,91 @@ public class ConnectionRegressionTest ex
}
}
}
+ public void testUnreliableSocketFactory() throws Exception {
+ Properties props = new Properties();
+ props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory");
+ props.setProperty("loadBalanceStrategy", "bestResponseTime");
+ NonRegisteringDriver d = new NonRegisteringDriver();
+ String host = d.parseURL(BaseTestCase.dbUrl,
props).getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY);
+ if(host == null){
+ host = "localhost";
+ }
+
+ UnreliableSocketFactory.mapHost("first", host);
+ UnreliableSocketFactory.mapHost("second", host);
+
+ Connection conn = getConnectionWithProps("jdbc:mysql:loadbalance://first,second/test",
props);
+ assertNotNull("Connection should not be null", conn);
+ try {
+ conn.createStatement().execute("SELECT 1");
+ conn.createStatement().execute("SELECT 1");
+ // both connections are live now
+ UnreliableSocketFactory.downHost("first");
+ UnreliableSocketFactory.downHost("second");
+ try{
+ conn.createStatement().execute("SELECT 1");
+ fail("Should hang here.");
+ } catch (SQLException sqlEx){
+ assertEquals("08S01", sqlEx.getSQLState());
+ }
+ } finally {
+ closeMemberJDBCResources();
+ }
+ }
+
+ public void testBug43421() throws Exception {
+ Properties props = new Properties();
+ props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory");
+ props.setProperty("bestResponse", "bestResponseTime");
+ NonRegisteringDriver d = new NonRegisteringDriver();
+ Properties testCaseProps = d.parseURL(BaseTestCase.dbUrl, null);
+ String host = testCaseProps.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY);
+ String db = testCaseProps.getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
+ if(host == null){
+ host = "localhost";
+ }
+ UnreliableSocketFactory.mapHost("first", host);
+ UnreliableSocketFactory.mapHost("second", host);
+
+ Connection conn = getConnectionWithProps("jdbc:mysql:loadbalance://first,second/" + db,
props);
+ assertNotNull("Connection should not be null", conn);
+
+ try {
+ conn.createStatement().execute("SELECT 1");
+ conn.createStatement().execute("SELECT 1");
+ // both connections are live now
+ UnreliableSocketFactory.downHost("second");
+ try{
+ conn.createStatement().execute("/* ping */");
+ fail("Pings will not succeed when one host is down and using loadbalance w/o global
blacklist.");
+ } catch (SQLException sqlEx){
+ }
+ } finally {
+ closeMemberJDBCResources();
+ }
+
+ UnreliableSocketFactory.flushAllHostLists();
+ props = new Properties();
+ props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory");
+ props.setProperty("loadBalanceStrategy", "bestResponseTime");
+ props.setProperty("globalBlacklistTimeout", "200");
+
+ conn = getConnectionWithProps("jdbc:mysql:loadbalance://first,second/" + db, props);
+ assertNotNull("Connection should not be null", conn);
+
+ try {
+ conn.createStatement().execute("SELECT 1");
+ conn.createStatement().execute("SELECT 1");
+ // both connections are live now
+ UnreliableSocketFactory.downHost("second");
+ try{
+ conn.createStatement().execute("/* ping */");
+ } catch (SQLException sqlEx){
+ fail("Pings should succeed even though host is down.");
+ }
+ } finally {
+ closeMemberJDBCResources();
+ }
+
+ }
}
\ No newline at end of file
| Thread |
|---|
| • bzr push into connector-j/branches/branch_5_1 branch (todd.farmer:764to 765) Bug#43421 | Todd Farmer | 6 Mar 2009 |