From: fhanik
Date: Fri, 13 Nov 2009 21:53:13 +0000 (+0000)
Subject: Implement suspectTimeout to allow JMX notifications and log events to take place...
X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=efac0c9487154aafd3e344ab6d7737546264958f;p=tomcat7.0
Implement suspectTimeout to allow JMX notifications and log events to take place if a connection is checked out for too long. But don't abandon/close the connection.
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@836011 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/modules/jdbc-pool/.classpath b/modules/jdbc-pool/.classpath
index 6983e0db6..ef54a92d6 100644
--- a/modules/jdbc-pool/.classpath
+++ b/modules/jdbc-pool/.classpath
@@ -6,5 +6,6 @@
+
diff --git a/modules/jdbc-pool/doc/jdbc-pool.xml b/modules/jdbc-pool/doc/jdbc-pool.xml
index c692de9a2..83e99b70c 100644
--- a/modules/jdbc-pool/doc/jdbc-pool.xml
+++ b/modules/jdbc-pool/doc/jdbc-pool.xml
@@ -78,13 +78,16 @@
Asynchronous connection retrieval - you can queue your request for a connection and receive a Future<Connection> back.
Better idle connection handling. Instead of closing connections directly, it can still pool connections and sizes the idle pool with a smarter algorithm.
You can decide at what moment connections are considered abandoned, is it when the pool is full, or directly at a timeout
- by specifying a threshold.
+ by specifying a pool usage threshold.
The abandon connection timer will reset upon a statement/query activity. Allowing a connections that is in use for a long time to not timeout.
This is achieved using the ResetAbandonedTimer
Close connections after they have been connected for a certain time. Age based close upon return to the pool.
-
+
+ Get JMX notifications and log entries when connections are suspected for being abandoned. This is similar to
+ the removeAbandonedTimeout but it doesn't take any action, only reports the information.
+ This is achieved using the suspectTimeout attribute.
@@ -388,6 +391,16 @@
The default value is true.
+
+ (int) Timeout value in seconds. Default value is 0.
+ Similar to to the removeAbandonedTimeout value but instead of treating the connection
+ as abandoned, and potentially closing the connection, this simply logs the warning if
+ logAbandoned is set to true. If this value is equal or less than 0, no suspect
+ checking will be performed. Suspect checking only takes place if the timeout value is larger than 0 and
+ the connection was not abandoned or if abandon check is disabled. If a connection is suspect a WARN message gets
+ logged and a JMX notification gets sent once.
+
+
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
index 1e25d926e..f44c0a5e9 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
@@ -475,6 +475,32 @@ public class ConnectionPool {
con.unlock();
}
}
+
+ /**
+ * thread safe way to abandon a connection
+ * signals a connection to be abandoned.
+ * this will disconnect the connection, and log the stack trace if logAbanded=true
+ * @param con PooledConnection
+ */
+ protected void suspect(PooledConnection con) {
+ if (con == null)
+ return;
+ if (con.isSuspect())
+ return;
+ try {
+ con.lock();
+ String trace = con.getStackTrace();
+ if (getPoolProperties().isLogAbandoned()) {
+ log.warn("Connection has been marked suspect, possibly abandoned " + con + "["+(System.currentTimeMillis()-con.getTimestamp())+" ms.]:" + trace);
+ }
+ if (jmxPool!=null) {
+ jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_ABANDONED_NOTIFICATION, trace);
+ }
+ con.setSuspect(true);
+ } finally {
+ con.unlock();
+ }
+ }
/**
* thread safe way to release a connection
@@ -786,8 +812,8 @@ public class ConnectionPool {
public void checkAbandoned() {
try {
if (busy.size()==0) return;
- if (!shouldAbandon()) return;
Iterator locked = busy.iterator();
+ int sto = getPoolProperties().getSuspectTimeout();
while (locked.hasNext()) {
PooledConnection con = locked.next();
boolean setToNull = false;
@@ -799,10 +825,12 @@ public class ConnectionPool {
continue;
long time = con.getTimestamp();
long now = System.currentTimeMillis();
- if ((now - time) > con.getAbandonTimeout()) {
+ if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
busy.remove(con);
abandon(con);
setToNull = true;
+ } else if (sto > 0 && (now - time) > (sto*1000)) {
+ suspect(con);
} else {
//do nothing
} //end if
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
index 093dd707a..1db507d29 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
@@ -516,6 +516,23 @@ public class DataSourceProxy implements PoolConfiguration {
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getSuspectTimeout() {
+ return getPoolProperties().getSuspectTimeout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSuspectTimeout(int seconds) {
+ getPoolProperties().setSuspectTimeout(seconds);
+ }
+
//===============================================================================
// Expose JMX attributes through Tomcat's dynamic reflection
//===============================================================================
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
index 667ae627b..d325323f0 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java
@@ -698,5 +698,24 @@ public interface PoolConfiguration {
* @param useLock set to true if a lock should be used on connection operations
*/
public void setUseLock(boolean useLock);
+
+ /**
+ * Similar to {@link #setRemoveAbandonedTimeout(int)} but instead of treating the connection
+ * as abandoned, and potentially closing the connection, this simply logs the warning if
+ * {@link #isLogAbandoned()} returns true. If this value is equal or less than 0, no suspect
+ * checking will be performed. Suspect checking only takes place if the timeout value is larger than 0 and
+ * the connection was not abandoned or if abandon check is disabled. If a connection is suspect a WARN message gets
+ * logged and a JMX notification gets sent once.
+ * @param seconds - the amount of time in seconds that has to pass before a connection is marked suspect.
+ */
+ public void setSuspectTimeout(int seconds);
+
+ /**
+ * Returns the time in seconds to pass before a connection is marked an abanoned suspect.
+ * Any value lesser than or equal to 0 means the check is disabled.
+ * @return Returns the time in seconds to pass before a connection is marked an abanoned suspect.
+ */
+ public int getSuspectTimeout();
+
}
\ No newline at end of file
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
index 0f5661705..62b31c556 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
@@ -74,6 +74,8 @@ public class PoolProperties implements PoolConfiguration {
protected long maxAge = 0;
protected boolean useLock = false;
private InterceptorDefinition[] interceptors = null;
+ protected int suspectTimeout = 0;
+
/**
* {@inheritDoc}
@@ -718,14 +720,32 @@ public class PoolProperties implements PoolConfiguration {
return defaultReadOnly;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getSuspectTimeout() {
+ return this.suspectTimeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSuspectTimeout(int seconds) {
+ this.suspectTimeout = seconds;
+ }
+
/**
* {@inheritDoc}
*/
@Override
public boolean isPoolSweeperEnabled() {
- boolean result = getTimeBetweenEvictionRunsMillis()>0;
- result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
- result = result || (isTestWhileIdle() && getValidationQuery()!=null);
+ boolean timer = getTimeBetweenEvictionRunsMillis()>0;
+ boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
+ result = result || (timer && getSuspectTimeout()>0);
+ result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null);
return result;
}
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
index ba8edbf21..eff788dcd 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
@@ -111,6 +111,8 @@ public class PooledConnection {
private AtomicBoolean released = new AtomicBoolean(false);
+ private volatile boolean suspect = false;
+
/**
* Constructor
* @param prop - pool properties
@@ -390,6 +392,18 @@ public class PooledConnection {
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
+ setSuspect(false);
+ }
+
+
+
+
+ public boolean isSuspect() {
+ return suspect;
+ }
+
+ public void setSuspect(boolean suspect) {
+ this.suspect = suspect;
}
/**
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java
index 412885e01..31b7ed2d3 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java
@@ -73,7 +73,7 @@ public abstract class AbstractQueryReport extends AbstractCreateStatementInterce
* Invoked when a query execution, a call to execute/executeQuery or executeBatch failed.
* @param query the query that was executed and failed
* @param args the arguments to the execution
- * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#executes}
+ * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
* @param start the time the query execution started
* @param t the exception that happened
* @return - the SQL that was executed or the string "batch" if it was a batch execution
@@ -92,7 +92,7 @@ public abstract class AbstractQueryReport extends AbstractCreateStatementInterce
* Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was within the timing threshold
* @param query the query that was executed and failed
* @param args the arguments to the execution
- * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#executes}
+ * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
* @param start the time the query execution started
* @param delta the time the execution took
* @return - the SQL that was executed or the string "batch" if it was a batch execution
@@ -111,7 +111,7 @@ public abstract class AbstractQueryReport extends AbstractCreateStatementInterce
* Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded and was exceeded the timing threshold
* @param query the query that was executed and failed
* @param args the arguments to the execution
- * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#executes}
+ * @param name the name of the method used to execute {@link AbstractCreateStatementInterceptor#isExecute(Method, boolean)}
* @param start the time the query execution started
* @param delta the time the execution took
* @return - the SQL that was executed or the string "batch" if it was a batch execution
diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
index fbfb21b8c..d53e491f9 100644
--- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
+++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
@@ -72,6 +72,7 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co
public static final String NOTIFY_ABANDON = "CONNECTION ABANDONED";
public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY";
public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY";
+ public static final String SUSPECT_ABANDONED_NOTIFICATION = "SUSPECT CONNETION ABANDONED";
@@ -86,7 +87,7 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co
}
public static MBeanNotificationInfo[] getDefaultNotificationInfo() {
- String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION, FAILED_QUERY_NOTIFICATION};
+ String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION, FAILED_QUERY_NOTIFICATION, SUSPECT_ABANDONED_NOTIFICATION};
String name = Notification.class.getName();
String description = "A connection pool error condition was met.";
MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
@@ -553,5 +554,21 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co
// TODO Auto-generated method stub
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getSuspectTimeout() {
+ return getPoolProperties().getSuspectTimeout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSuspectTimeout(int seconds) {
+ //no op
+ }
}