Author: markt Date: Thu Jul 25 13:10:04 2013 New Revision: 1506954 URL: http://svn.apache.org/r1506954 Log: DBCP-229 Make stack trace of borrowing available to help ID leaks. This change makes some information available about objects in the pool (borrowed and idle) via JMX. More information can be exposed if required.
Added: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfo.java (with props) commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfoMBean.java (with props) commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMXBean.java - copied, changed from r1506497, commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java Removed: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java Modified: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/PooledObject.java commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObject.java commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java Modified: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/PooledObject.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/PooledObject.java?rev=1506954&r1=1506953&r2=1506954&view=diff ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/PooledObject.java (original) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/PooledObject.java Thu Jul 25 13:10:04 2013 @@ -16,6 +16,7 @@ */ package org.apache.commons.pool2; +import java.io.PrintWriter; import java.util.Deque; /** @@ -120,10 +121,17 @@ public interface PooledObject<T> extends void invalidate(); /** - * Prints the stack trace of the code that created this pooled object to - * the configured log writer. Does nothing if no log writer has been set. + * Is abandoned object tracking being used? If this is true the + * implementation will need to record the stack trace of the last caller to + * borrow this object. */ - void printStackTrace(); + void setLogAbandoned(boolean logAbandoned); + + /** + * Prints the stack trace of the code that borrowed this pooled object to + * the supplied writer. + */ + void printStackTrace(PrintWriter writer); /** * Returns the state of this object. @@ -140,4 +148,6 @@ public interface PooledObject<T> extends * Marks the object as returning to the pool. */ void markReturning(); + + } Modified: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObject.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObject.java?rev=1506954&r1=1506953&r2=1506954&view=diff ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObject.java (original) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObject.java Thu Jul 25 13:10:04 2013 @@ -20,7 +20,6 @@ import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Deque; -import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectState; @@ -45,9 +44,8 @@ public class DefaultPooledObject<T> impl private final long createTime = System.currentTimeMillis(); private volatile long lastBorrowTime = createTime; private volatile long lastReturnTime = createTime; - private AtomicBoolean abandonedLogConfigured = new AtomicBoolean(false); + private volatile boolean logAbandoned = false; private Exception borrowedBy = null; - private PrintWriter logWriter = null; public DefaultPooledObject(T object) { this.object = object; @@ -216,7 +214,7 @@ public class DefaultPooledObject<T> impl if (state == PooledObjectState.IDLE) { state = PooledObjectState.ALLOCATED; lastBorrowTime = System.currentTimeMillis(); - if (abandonedLogConfigured.get()) { + if (logAbandoned) { borrowedBy = new AbandonedObjectException(); } return true; @@ -242,7 +240,7 @@ public class DefaultPooledObject<T> impl state == PooledObjectState.RETURNING) { state = PooledObjectState.IDLE; lastReturnTime = System.currentTimeMillis(); - if (abandonedLogConfigured.get()) { + if (borrowedBy != null) { borrowedBy = null; } return true; @@ -261,13 +259,12 @@ public class DefaultPooledObject<T> impl /** * Prints the stack trace of the code that borrowed this pooled object to - * the configured log writer. Does nothing of no PrintWriter was supplied - * to the constructor. + * the supplied writer. */ @Override - public void printStackTrace() { - if (borrowedBy != null && logWriter != null) { - borrowedBy.printStackTrace(logWriter); + public void printStackTrace(PrintWriter writer) { + if (borrowedBy != null) { + borrowedBy.printStackTrace(writer); } } @@ -296,16 +293,9 @@ public class DefaultPooledObject<T> impl state = PooledObjectState.RETURNING; } - /** - * Only has an effect on the first invocation. Subsequent invocations are - * ignored. - */ - void setAbandonedLoqWriter(PrintWriter logWriter) { - if (abandonedLogConfigured.compareAndSet(false, true)) { - if (logWriter != null) { - this.logWriter = logWriter; - } - } + @Override + public void setLogAbandoned(boolean logAbandoned) { + this.logAbandoned = logAbandoned; } static class AbandonedObjectException extends Exception { @@ -315,8 +305,8 @@ public class DefaultPooledObject<T> impl /** Date format */ //@GuardedBy("this") private static final SimpleDateFormat format = new SimpleDateFormat - ("'Pooled object created' yyyy-MM-dd HH:mm:ss " + - "'by the following code was never returned to the pool:'"); + ("'Pooled object created' yyyy-MM-dd HH:mm:ss Z " + + "'by the following code has not been returned to the pool:'"); private final long _createdTime; Added: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfo.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfo.java?rev=1506954&view=auto ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfo.java (added) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfo.java Thu Jul 25 13:10:04 2013 @@ -0,0 +1,56 @@ +package org.apache.commons.pool2.impl; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.text.SimpleDateFormat; + +import org.apache.commons.pool2.PooledObject; + +public class DefaultPooledObjectInfo implements DefaultPooledObjectInfoMBean { + + private final PooledObject<?> pooledObject; + + public DefaultPooledObjectInfo(PooledObject<?> pooledObject) { + this.pooledObject = pooledObject; + } + + @Override + public long getCreateTime() { + return pooledObject.getCreateTime(); + } + + @Override + public String getCreateTimeFormatted() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + return sdf.format(Long.valueOf(pooledObject.getCreateTime())); + } + + @Override + public long getLastBorrowTime() { + return pooledObject.getLastBorrowTime(); + } + + @Override + public String getLastBorrowTimeFormatted() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + return sdf.format(Long.valueOf(pooledObject.getLastBorrowTime())); + } + + @Override + public String getLastBorrowTrace() { + StringWriter sw = new StringWriter(); + pooledObject.printStackTrace(new PrintWriter(sw)); + return sw.toString(); + } + + @Override + public long getLastReturnTime() { + return pooledObject.getLastReturnTime(); + } + + @Override + public String getLastReturnTimeFormatted() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + return sdf.format(Long.valueOf(pooledObject.getLastReturnTime())); + } +} Propchange: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfo.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfoMBean.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfoMBean.java?rev=1506954&view=auto ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfoMBean.java (added) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfoMBean.java Thu Jul 25 13:10:04 2013 @@ -0,0 +1,11 @@ +package org.apache.commons.pool2.impl; + +public interface DefaultPooledObjectInfoMBean { + long getCreateTime(); + String getCreateTimeFormatted(); + long getLastBorrowTime(); + String getLastBorrowTimeFormatted(); + String getLastBorrowTrace(); + long getLastReturnTime(); + String getLastReturnTimeFormatted(); +} Propchange: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/DefaultPooledObjectInfoMBean.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java?rev=1506954&r1=1506953&r2=1506954&view=diff ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java (original) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java Thu Jul 25 13:10:04 2013 @@ -991,10 +991,6 @@ public class GenericKeyedObjectPool<K,T> throw e; } - if (p instanceof DefaultPooledObject) { - ((DefaultPooledObject<T> )p).setAbandonedLoqWriter(null); - } - createdCount.incrementAndGet(); objectDeque.getAllObjects().put(p.getObject(), p); return p; Modified: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java?rev=1506954&r1=1506953&r2=1506954&view=diff ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java (original) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java Thu Jul 25 13:10:04 2013 @@ -17,9 +17,11 @@ package org.apache.commons.pool2.impl; import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; @@ -73,7 +75,7 @@ import org.apache.commons.pool2.TrackedU * @since 2.0 */ public class GenericObjectPool<T> extends BaseGenericObjectPool<T> - implements ObjectPool<T>, GenericObjectPoolMBean { + implements ObjectPool<T>, GenericObjectPoolMXBean { /** * Create a new <code>GenericObjectPool</code> using defaults from @@ -790,13 +792,8 @@ public class GenericObjectPool<T> extend throw e; } - if (p instanceof DefaultPooledObject) { - if (isAbandonedConfig() && abandonedConfig.getLogAbandoned()) { - ((DefaultPooledObject<T> )p).setAbandonedLoqWriter( - abandonedConfig.getLogWriter()); - } else { - ((DefaultPooledObject<T> )p).setAbandonedLoqWriter(null); - } + if (isAbandonedConfig() && abandonedConfig.getLogAbandoned()) { + p.setLogAbandoned(true); } createdCount.incrementAndGet(); @@ -901,7 +898,7 @@ public class GenericObjectPool<T> extend while (itr.hasNext()) { PooledObject<T> pooledObject = itr.next(); if (abandonedConfig.getLogAbandoned()) { - pooledObject.printStackTrace(); + pooledObject.printStackTrace(abandonedConfig.getLogWriter()); } try { invalidateObject(pooledObject.getObject()); @@ -927,6 +924,15 @@ public class GenericObjectPool<T> extend } } + @Override + public Set<DefaultPooledObjectInfo> getAllObjects() { + Set<DefaultPooledObjectInfo> result = + new HashSet<DefaultPooledObjectInfo>(allObjects.size()); + for (PooledObject<T> p : allObjects.values()) { + result.add(new DefaultPooledObjectInfo(p)); + } + return result; + } // --- configuration attributes -------------------------------------------- Copied: commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMXBean.java (from r1506497, commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java) URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMXBean.java?p2=commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMXBean.java&p1=commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java&r1=1506497&r2=1506954&rev=1506954&view=diff ============================================================================== --- commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java (original) +++ commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2/impl/GenericObjectPoolMXBean.java Thu Jul 25 13:10:04 2013 @@ -16,6 +16,8 @@ */ package org.apache.commons.pool2.impl; +import java.util.Set; + /** * Defines the methods that will be made available via JMX. * @@ -23,7 +25,7 @@ package org.apache.commons.pool2.impl; * * @since 2.0 */ -public interface GenericObjectPoolMBean { +public interface GenericObjectPoolMXBean { // Getters for basic configuration settings /** * See {@link GenericObjectPool#getBlockWhenExhausted()} @@ -138,12 +140,12 @@ public interface GenericObjectPoolMBean * See {@link GenericObjectPool#getNumWaiters()} */ int getNumWaiters(); - + // Getters for abandoned object removal configuration /** * See {@link GenericObjectPool#isAbandonedConfig()} */ - boolean isAbandonedConfig(); + boolean isAbandonedConfig(); /** * See {@link GenericObjectPool#getLogAbandoned()} */ @@ -160,4 +162,8 @@ public interface GenericObjectPoolMBean * See {@link GenericObjectPool#getRemoveAbandonedTimeout()} */ int getRemoveAbandonedTimeout(); + /** + * See {@link GenericObjectPool#getAllObjects()} + */ + Set<DefaultPooledObjectInfo> getAllObjects(); }