apply fix for: https://issues.apache.org/jira/browse/AMQ-3482 to return default behavior to blocking.

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1164058 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Timothy A. Bish 2011-09-01 13:02:28 +00:00
parent 588a3c3594
commit 5ac1540c63
2 changed files with 115 additions and 127 deletions

View File

@ -66,7 +66,7 @@ public class PooledConnectionFactory implements ConnectionFactory, Service {
private int maximumActive = 500; private int maximumActive = 500;
private int maxConnections = 1; private int maxConnections = 1;
private int idleTimeout = 30 * 1000; private int idleTimeout = 30 * 1000;
private boolean blockIfSessionPoolIsFull = false; private boolean blockIfSessionPoolIsFull = true;
private AtomicBoolean stopped = new AtomicBoolean(false); private AtomicBoolean stopped = new AtomicBoolean(false);
private long expiryTimeout = 0l; private long expiryTimeout = 0l;
@ -197,23 +197,19 @@ public class PooledConnectionFactory implements ConnectionFactory, Service {
} }
/** /**
* Controls the behavior of the internal session pool. * Controls the behavior of the internal session pool. By default the call to
* By default the call to Connection.getSession() will * Connection.getSession() will block if the session pool is full. If the
* return a JMSException if the session pool is full. * argument false is given, it will change the default behavior and instead the
* If the argument true is given, it will change the * call to getSession() will throw a JMSException.
* default behavior and instead the call to getSession()
* will block until a session is available in the pool, which
* used to be the default behavior in ActiveMQ versions < 5.6.
* *
* The size of the session pool is controlled by the @see #maximumActive * The size of the session pool is controlled by the @see #maximumActive
* property. * property.
* *
* @param block - if true, the call to getSession() blocks if the pool * @param block - if true, the call to getSession() blocks if the pool is full
* is full until a session object is available. * until a session object is available. defaults to true.
* defaults to false.
*/ */
public void setBlockIfSessionPoolIsFull(boolean block) { public void setBlockIfSessionPoolIsFull(boolean block) {
this.blockIfSessionPoolIsFull = block; this.blockIfSessionPoolIsFull = block;
} }
/** /**
@ -237,14 +233,14 @@ public class PooledConnectionFactory implements ConnectionFactory, Service {
* @return the newly created but empty ObjectPoolFactory * @return the newly created but empty ObjectPoolFactory
*/ */
protected ObjectPoolFactory createPoolFactory() { protected ObjectPoolFactory createPoolFactory() {
if (blockIfSessionPoolIsFull) { if (blockIfSessionPoolIsFull) {
return new GenericObjectPoolFactory(null, maximumActive); return new GenericObjectPoolFactory(null, maximumActive);
} else { } else {
return new GenericObjectPoolFactory(null, return new GenericObjectPoolFactory(null,
maximumActive, maximumActive,
GenericObjectPool.WHEN_EXHAUSTED_FAIL, GenericObjectPool.WHEN_EXHAUSTED_FAIL,
GenericObjectPool.DEFAULT_MAX_WAIT); GenericObjectPool.DEFAULT_MAX_WAIT);
} }
} }
public int getIdleTimeout() { public int getIdleTimeout() {

View File

@ -31,7 +31,7 @@ import org.apache.log4j.Logger;
*/ */
public class PooledConnectionFactoryTest extends TestCase public class PooledConnectionFactoryTest extends TestCase
{ {
public final static Logger LOG = Logger.getLogger(PooledConnectionFactoryTest.class); public final static Logger LOG = Logger.getLogger(PooledConnectionFactoryTest.class);
/** /**
@ -54,94 +54,86 @@ public class PooledConnectionFactoryTest extends TestCase
/** /**
* Tests the behavior of the sessionPool of the PooledConnectionFactory * Tests the behavior of the sessionPool of the PooledConnectionFactory
* when maximum number of sessions are reached. In older versions the call to * when maximum number of sessions are reached.
* Connection.createSession() would simply block indefinitely if the maximum
* number of sessions got reached (controled by
* PooledConnectionFactory.setMaximumActive()).
* Rather than blocking the entire thread, it should raise an exception
* instead.
*/ */
public void testApp() throws Exception public void testApp() throws Exception
{ {
// using separate thread for testing so that we can interrupt the test // using separate thread for testing so that we can interrupt the test
// if the call to get a new session blocks. // if the call to get a new session blocks.
// start test runner thread // start test runner thread
ExecutorService executor = Executors.newSingleThreadExecutor(); ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Boolean> result = (Future<Boolean>) executor.submit(new TestRunner()); Future<Boolean> result = (Future<Boolean>) executor.submit(new TestRunner());
// test should not take > 5secs, so test fails i // test should not take > 5secs, so test fails i
Thread.sleep(5*1000); Thread.sleep(5*1000);
if (!result.isDone() || !result.get().booleanValue()) { if (!result.isDone() || !result.get().booleanValue()) {
PooledConnectionFactoryTest.LOG.error("2nd call to createSession()" + PooledConnectionFactoryTest.LOG.error("2nd call to createSession()" +
" is blocking but should have returned an error instead."); " is blocking but should have returned an error instead.");
executor.shutdownNow(); executor.shutdownNow();
Assert.fail("SessionPool inside PooledConnectionFactory is blocking if " + Assert.fail("SessionPool inside PooledConnectionFactory is blocking if " +
"limit is exceeded but should return an exception instead."); "limit is exceeded but should return an exception instead.");
} }
} }
} }
class TestRunner implements Callable<Boolean> { class TestRunner implements Callable<Boolean> {
public final static Logger LOG = Logger.getLogger(TestRunner.class); public final static Logger LOG = Logger.getLogger(TestRunner.class);
/** /**
* @return true if test succeeded, false otherwise * @return true if test succeeded, false otherwise
*/ */
public Boolean call() { public Boolean call() {
Connection conn = null; Connection conn = null;
Session one = null; Session one = null;
// wait at most 5 seconds for the call to createSession // wait at most 5 seconds for the call to createSession
try { try {
ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory("vm://broker1?marshal=false&broker.persistent=false"); ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory("vm://broker1?marshal=false&broker.persistent=false");
PooledConnectionFactory cf = new PooledConnectionFactory(amq); PooledConnectionFactory cf = new PooledConnectionFactory(amq);
cf.setMaxConnections(3); cf.setMaxConnections(3);
cf.setMaximumActive(1); cf.setMaximumActive(1);
cf.setBlockIfSessionPoolIsFull(false);
// default should be false already but lets make sure a change to the default conn = cf.createConnection();
// setting does not make this test fail. one = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
cf.setBlockIfSessionPoolIsFull(false);
conn = cf.createConnection(); Session two = null;
one = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); try {
// this should raise an exception as we called setMaximumActive(1)
two = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
two.close();
Session two = null; LOG.error("Expected JMSException wasn't thrown.");
try { Assert.fail("seconds call to Connection.createSession() was supposed" +
// this should raise an exception as we called setMaximumActive(1) "to raise an JMSException as internal session pool" +
two = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); "is exhausted. This did not happen and indiates a problem");
two.close(); return new Boolean(false);
} catch (JMSException ex) {
if (ex.getCause().getClass() == java.util.NoSuchElementException.class) {
//expected, ignore but log
LOG.info("Caught expected " + ex);
} else {
LOG.error(ex);
return new Boolean(false);
}
} finally {
if (one != null)
one.close();
if (conn != null)
conn.close();
}
} catch (Exception ex) {
LOG.error(ex.getMessage());
return new Boolean(false);
}
LOG.error("Expected JMSException wasn't thrown."); // all good, test succeeded
Assert.fail("seconds call to Connection.createSession() was supposed" + return new Boolean(true);
"to raise an JMSException as internal session pool" + }
"is exhausted. This did not happen and indiates a problem");
return new Boolean(false);
} catch (JMSException ex) {
if (ex.getCause().getClass() == java.util.NoSuchElementException.class) {
//expected, ignore but log
LOG.info("Caught expected " + ex);
} else {
LOG.error(ex);
return new Boolean(false);
}
} finally {
if (one != null)
one.close();
if (conn != null)
conn.close();
}
} catch (Exception ex) {
LOG.error(ex.getMessage());
return new Boolean(false);
}
// all good, test succeeded
return new Boolean(true);
}
} }