List:Commits« Previous MessageNext Message »
From:Todd Farmer Date:March 6 2009 10:58pm
Subject:bzr push into connector-j/branches/branch_5_1 branch (todd.farmer:764
to 765) Bug#43421
View as plain text  
  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#43421Todd Farmer6 Mar 2009