Skip to content
Permalink
Browse files
GERONIMO-3834 Fix the permit leak when connections can't be created. …
…Simplify some of the pool code and add some pool tests for permit count and resizing

git-svn-id: https://svn.apache.org/repos/asf/geronimo/components/txmanager/trunk@620093 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
djencks committed Feb 9, 2008
1 parent ab61ddf commit f9f0a579a053a2fc298f5be39cc35798488c6089
Showing 8 changed files with 496 additions and 348 deletions.
@@ -28,6 +28,7 @@
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.ManagedConnection;
import javax.security.auth.Subject;

import org.apache.commons.logging.Log;
@@ -75,7 +76,12 @@ public void getConnection(ConnectionInfo connectionInfo) throws ResourceExceptio
resizeLock.readLock().lock();
try {
if (permits.tryAcquire(blockingTimeoutMilliseconds, TimeUnit.MILLISECONDS)) {
internalGetConnection(connectionInfo);
try {
internalGetConnection(connectionInfo);
} catch (ResourceException e) {
permits.release();
throw e;
}
} else {
throw new ResourceException("No ManagedConnections available "
+ "within configured blocking timeout ( "
@@ -120,17 +126,55 @@ public void returnConnection(ConnectionInfo connectionInfo,
return;
}

boolean wasInPool = internalReturn(connectionInfo, connectionReturnAction);
boolean releasePermit = internalReturn(connectionInfo, connectionReturnAction);

if (!wasInPool) {
if (releasePermit) {
permits.release();
}
} finally {
resizeLock.readLock().unlock();
}
}

protected abstract boolean internalReturn(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction);
protected boolean internalReturn(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction) {
ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
ManagedConnection mc = mci.getManagedConnection();
try {
mc.cleanup();
} catch (ResourceException e) {
connectionReturnAction = ConnectionReturnAction.DESTROY;
}

boolean releasePermit;
synchronized (getPool()) {
// a bit redundant, but this closes a small timing hole...
if (destroyed) {
try {
mc.destroy();
}
catch (ResourceException re) {
//ignore
}
return doRemove(mci);
}
if (shrinkLater > 0) {
//nothing can get in the pool while shrinkLater > 0, so releasePermit is false here.
connectionReturnAction = ConnectionReturnAction.DESTROY;
shrinkLater--;
releasePermit = false;
} else if (connectionReturnAction == ConnectionReturnAction.RETURN_HANDLE) {
mci.setLastUsed(System.currentTimeMillis());
doAdd(mci);
return true;
} else {
releasePermit = doRemove(mci);
}
}
//we must destroy connection.
next.returnConnection(connectionInfo, connectionReturnAction);
connectionCount--;
return releasePermit;
}

protected abstract void internalDestroy();

@@ -147,7 +191,9 @@ public int getPartitionCount() {
return 1;
}

public abstract int getPartitionMaxSize();
public int getPartitionMaxSize() {
return maxSize;
}

public void setPartitionMaxSize(int newMaxSize) throws InterruptedException {
if (newMaxSize <= 0) {
@@ -157,22 +203,30 @@ public void setPartitionMaxSize(int newMaxSize) throws InterruptedException {
resizeLock.writeLock().lock();
try {
ResizeInfo resizeInfo = new ResizeInfo(this.minSize, permits.availablePermits(), connectionCount, newMaxSize);
this.shrinkLater = resizeInfo.getShrinkLater();

permits = new Semaphore(newMaxSize, true);
//pre-acquire permits for the existing checked out connections that will not be closed when they are returned.
for (int i = 0; i < resizeInfo.getTransferCheckedOut(); i++) {
permits.acquire();
}
//make sure shrinkLater is 0 while discarding excess connections
this.shrinkLater = 0;
//transfer connections we are going to keep
transferConnections(newMaxSize, resizeInfo.getShrinkNow());
this.shrinkLater = resizeInfo.getShrinkLater();
this.minSize = resizeInfo.getNewMinSize();
this.maxSize = newMaxSize;
} finally {
resizeLock.writeLock().unlock();
}
}
}

protected abstract boolean doRemove(ManagedConnectionInfo mci);

protected abstract void doAdd(ManagedConnectionInfo mci);

protected abstract Object getPool();


static final class ResizeInfo {

@@ -271,7 +325,17 @@ public void setIdleTimeoutMinutes(int idleTimeoutMinutes) {

protected abstract void getExpiredManagedConnectionInfos(long threshold, List<ManagedConnectionInfo> killList);

protected abstract boolean addToPool(ManagedConnectionInfo mci);
protected boolean addToPool(ManagedConnectionInfo mci) {
boolean added;
synchronized (getPool()) {
connectionCount++;
added = getPartitionMaxSize() > getIdleConnectionCount();
if (added) {
doAdd(mci);
}
}
return added;
}

// static class to permit chain of strong references from preventing ClassLoaders
// from being GC'ed.
@@ -45,8 +45,7 @@ public void getConnection(ConnectionInfo connectionInfo) throws ResourceExceptio
}

try {
ManagedConnection mc =
mci.getManagedConnectionFactory().createManagedConnection(
ManagedConnection mc = mci.getManagedConnectionFactory().createManagedConnection(
mci.getSubject(),
mci.getConnectionRequestInfo());
mci.setManagedConnection(mc);

0 comments on commit f9f0a57

Please sign in to comment.