noel 2004/04/16 07:49:48 Modified: src/java/org/apache/james/util/mordred Tag: branch_2_1_fcs JdbcDataSource.java Log: Attempt to fix JAMES-254. Change to ArrayList from Vector, and simplify synchronization. This version has been tested with JDK 1.4.2 and works, but still fails with 1.4.1. All threads that call getConnection block on the synchronized(pool) statement, even though no thread owns it. Dain Sundstrom reports that this was a known problem with Hotspot (possibly just server) 1.4.0 and 1.4.1. Revision Changes Path No revision No revision 1.18.4.8 +123 -124 james-server/src/java/org/apache/james/util/mordred/JdbcDataSource.java Index: JdbcDataSource.java =================================================================== RCS file: /home/cvs/james-server/src/java/org/apache/james/util/mordred/JdbcDataSource.java,v retrieving revision 1.18.4.7 retrieving revision 1.18.4.8 diff -u -r1.18.4.7 -r1.18.4.8 --- JdbcDataSource.java 14 Apr 2004 18:10:49 -0000 1.18.4.7 +++ JdbcDataSource.java 16 Apr 2004 14:49:48 -0000 1.18.4.8 @@ -23,7 +23,7 @@ import java.sql.Connection; import java.sql.SQLException; -import java.util.Vector; +import java.util.ArrayList; import org.apache.avalon.excalibur.datasource.DataSourceComponent; import org.apache.avalon.framework.activity.Disposable; @@ -92,7 +92,7 @@ // Maximum number of connections to have open at any point private int maxConn = 0; // collection of connection objects - private Vector pool; + private ArrayList pool; // Thread that checks for dead/aged connections and removes them from pool private Thread reaper; // Flag to indicate whether reaper thread should run @@ -129,7 +129,7 @@ for(int attempts = 1; attempts <= 100; attempts++) { synchronized(pool) { for(int i = 0; i < pool.size(); i++) { - PoolConnEntry entry = (PoolConnEntry)pool.elementAt(i); + PoolConnEntry entry = (PoolConnEntry)pool.get(i); //Set the appropriate flags to make this connection //marked as in use try { @@ -153,58 +153,58 @@ } //we were unable to get a lock on this entry.. so continue through list } //loop through existing connections - } - //If we have 0, create another - if(DEEP_DEBUG) { - System.out.println(pool.size()); - } - try { - if(pool.size() == 0) { - //create a connection - PoolConnEntry entry = createConn(); - if(entry != null) { - if(DEEP_DEBUG) { - StringBuffer deepDebugBuffer = - new StringBuffer(128) - .append((new java.util.Date()).toString()) - .append(" returning new connection (") - .append(count) - .append(")"); - System.out.println(deepDebugBuffer.toString()); - } - return entry; - } - //looks like a connection was already created - } else { - //Since we didn't find one, and we have < max connections, then consider whether - // we create another - //if we've hit the 3rd attempt without getting a connection, - // let's create another to anticipate a slow down - if((attempts == 2) && (pool.size() < maxConn || maxConn == 0)) { + //If we have 0, create another + if(DEEP_DEBUG) { + System.out.println(pool.size()); + } + try { + if(pool.size() == 0) { + //create a connection PoolConnEntry entry = createConn(); if(entry != null) { if(DEEP_DEBUG) { StringBuffer deepDebugBuffer = - new StringBuffer(32) + new StringBuffer(128) + .append((new java.util.Date()).toString()) .append(" returning new connection (") .append(count) .append(")"); System.out.println(deepDebugBuffer.toString()); } return entry; - } else { - attempts = 1; + } + //looks like a connection was already created + } else { + //Since we didn't find one, and we have < max connections, then consider whether + // we create another + //if we've hit the 3rd attempt without getting a connection, + // let's create another to anticipate a slow down + if((attempts == 2) && (pool.size() < maxConn || maxConn == 0)) { + PoolConnEntry entry = createConn(); + if(entry != null) { + if(DEEP_DEBUG) { + StringBuffer deepDebugBuffer = + new StringBuffer(32) + .append(" returning new connection (") + .append(count) + .append(")"); + System.out.println(deepDebugBuffer.toString()); + } + return entry; + } else { + attempts = 1; + } } } - } - } catch(SQLException sqle) { - //Ignore... error creating the connection - StringWriter sout = new StringWriter(); - PrintWriter pout = new PrintWriter(sout, true); - pout.println("Error creating connection: "); - sqle.printStackTrace(pout); - if (getLogger().isErrorEnabled()) { - getLogger().error(sout.toString()); + } catch(SQLException sqle) { + //Ignore... error creating the connection + StringWriter sout = new StringWriter(); + PrintWriter pout = new PrintWriter(sout, true); + pout.println("Error creating connection: "); + sqle.printStackTrace(pout); + if (getLogger().isErrorEnabled()) { + getLogger().error(sout.toString()); + } } } //otherwise sleep 50ms 10 times, then create a connection @@ -271,7 +271,7 @@ //We don't show the password getLogger().debug("max connections = " + maxConn); } - pool = new Vector(); + pool = new ArrayList(); reaperActive = true; reaper = new Thread(this); reaper.setDaemon(true); @@ -389,61 +389,62 @@ public void run() { try { while(reaperActive) { - synchronized(pool) { for(int i = 0; i < pool.size(); i++) try { - PoolConnEntry entry = (PoolConnEntry)pool.elementAt(i); - long age = System.currentTimeMillis() - entry.getLastActivity(); - synchronized(entry) { - if((entry.getStatus() == PoolConnEntry.ACTIVE) && - (age > ACTIVE_CONN_HARD_TIME_LIMIT)) { - StringBuffer logBuffer = - new StringBuffer(128) - .append(" ***** connection ") - .append(entry.getId()) - .append(" is way too old: ") - .append(age) - .append(" > ") - .append(ACTIVE_CONN_HARD_TIME_LIMIT) - .append(" and will be closed."); - getLogger().info(logBuffer.toString()); - // This connection is way too old... - // kill it no matter what - finalizeEntry(entry); - continue; - } - if((entry.getStatus() == PoolConnEntry.ACTIVE) && - (age > ACTIVE_CONN_TIME_LIMIT)) { - StringBuffer logBuffer = - new StringBuffer(128) - .append(" ***** connection ") - .append(entry.getId()) - .append(" is way too old: ") - .append(age) - .append(" > ") - .append(ACTIVE_CONN_TIME_LIMIT); - getLogger().info(logBuffer.toString()); - // This connection is way too old... - // just log it for now. - continue; - } - if((entry.getStatus() == PoolConnEntry.AVAILABLE) && - (age > CONN_IDLE_LIMIT)) { - //We've got a connection that's too old... kill it - finalizeEntry(entry); - continue; + synchronized(pool) { + for(int i = 0; i < pool.size(); i++) try { + PoolConnEntry entry = (PoolConnEntry)pool.get(i); + long age = System.currentTimeMillis() - entry.getLastActivity(); + synchronized(entry) { + if((entry.getStatus() == PoolConnEntry.ACTIVE) && + (age > ACTIVE_CONN_HARD_TIME_LIMIT)) { + StringBuffer logBuffer = + new StringBuffer(128) + .append(" ***** connection ") + .append(entry.getId()) + .append(" is way too old: ") + .append(age) + .append(" > ") + .append(ACTIVE_CONN_HARD_TIME_LIMIT) + .append(" and will be closed."); + getLogger().info(logBuffer.toString()); + // This connection is way too old... + // kill it no matter what + finalizeEntry(entry); + continue; + } + if((entry.getStatus() == PoolConnEntry.ACTIVE) && + (age > ACTIVE_CONN_TIME_LIMIT)) { + StringBuffer logBuffer = + new StringBuffer(128) + .append(" ***** connection ") + .append(entry.getId()) + .append(" is way too old: ") + .append(age) + .append(" > ") + .append(ACTIVE_CONN_TIME_LIMIT); + getLogger().info(logBuffer.toString()); + // This connection is way too old... + // just log it for now. + continue; + } + if((entry.getStatus() == PoolConnEntry.AVAILABLE) && + (age > CONN_IDLE_LIMIT)) { + //We've got a connection that's too old... kill it + finalizeEntry(entry); + continue; + } } } - } - catch (Throwable ex) - { - StringWriter sout = new StringWriter(); - PrintWriter pout = new PrintWriter(sout, true); - pout.println("Reaper Error: "); - ex.printStackTrace(pout); - if (getLogger().isErrorEnabled()) { - getLogger().error(sout.toString()); + catch (Throwable ex) + { + StringWriter sout = new StringWriter(); + PrintWriter pout = new PrintWriter(sout, true); + pout.println("Reaper Error: "); + ex.printStackTrace(pout); + if (getLogger().isErrorEnabled()) { + getLogger().error(sout.toString()); + } } } - } try { // Check for activity every 5 seconds Thread.sleep(5000L); @@ -509,33 +510,31 @@ } return null; } - } - try { - entry = new PoolConnEntry(this, - java.sql.DriverManager.getConnection(jdbcURL, jdbcUsername, - jdbcPassword), - ++connectionCount); - if (getLogger().isDebugEnabled()) - { - getLogger().debug("Opening connection " + entry); - } - entry.lock(); - pool.addElement(entry); - return entry; - } catch(SQLException sqle) { - //Shouldn't ever happen, but it did, just return null. - // Exception from DriverManager.getConnection() - log it, and return null - StringWriter sout = new StringWriter(); - PrintWriter pout = new PrintWriter(sout, true); - pout.println("Error creating connection: "); - sqle.printStackTrace(pout); - if (getLogger().isErrorEnabled()) { - getLogger().error(sout.toString()); - } - return null; - } finally { - synchronized(pool) { - connCreationsInProgress--; + try { + entry = new PoolConnEntry(this, + java.sql.DriverManager.getConnection(jdbcURL, jdbcUsername, + jdbcPassword), + ++connectionCount); + if (getLogger().isDebugEnabled()) + { + getLogger().debug("Opening connection " + entry); + } + entry.lock(); + pool.add(entry); + return entry; + } catch(SQLException sqle) { + //Shouldn't ever happen, but it did, just return null. + // Exception from DriverManager.getConnection() - log it, and return null + StringWriter sout = new StringWriter(); + PrintWriter pout = new PrintWriter(sout, true); + pout.println("Error creating connection: "); + sqle.printStackTrace(pout); + if (getLogger().isErrorEnabled()) { + getLogger().error(sout.toString()); + } + return null; + } finally { + connCreationsInProgress--; } } } @@ -551,7 +550,7 @@ entry.finalize(); } catch(Exception fe) { } - pool.removeElement(entry); + pool.remove(entry); } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]