Author: fhanik Date: Fri Dec 26 15:14:13 2008 New Revision: 729554 URL: http://svn.apache.org/viewvc?rev=729554&view=rev Log: Refactor the query report for multi purpose
Added: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java Modified: tomcat/trunk/modules/jdbc-pool/build.xml tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java tomcat/trunk/modules/jdbc-pool/sign.sh Modified: tomcat/trunk/modules/jdbc-pool/build.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/build.xml?rev=729554&r1=729553&r2=729554&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/build.xml (original) +++ tomcat/trunk/modules/jdbc-pool/build.xml Fri Dec 26 15:14:13 2008 @@ -23,7 +23,7 @@ <!-- See "build.properties.sample" in the top level directory for all --> <property name="version.major" value="1" /> <property name="version.minor" value="0" /> - <property name="version.build" value="11" /> + <property name="version.build" value="12" /> <property name="version.patch" value="-beta" /> <property name="version" value="${version.major}.${version.minor}.${version.build}${version.patch}" /> <!-- property values you must customize for successful building!!! --> Added: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java?rev=729554&view=auto ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java (added) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/AbstractQueryReport.java Fri Dec 26 15:14:13 2008 @@ -0,0 +1,241 @@ +package org.apache.tomcat.jdbc.pool.interceptor; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.jdbc.pool.ConnectionPool; +import org.apache.tomcat.jdbc.pool.JdbcInterceptor; +import org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport.QueryStats; + +public abstract class AbstractQueryReport extends AbstractCreateStatementInterceptor { + //logger + protected static Log log = LogFactory.getLog(AbstractQueryReport.class); + + /** + * The threshold in milliseconds. If the query is faster than this, we don't measure it + */ + protected long threshold = 1000; //don't report queries less than this + + /** + * the constructors that are used to create statement proxies + */ + protected static final Constructor[] constructors = new Constructor[AbstractCreateStatementInterceptor.statements.length]; + + + public AbstractQueryReport() { + super(); + } + + + /** + * Invoked when prepareStatement has been called and completed. + * @param sql - the string used to prepare the statement with + * @param time - the time it took to invoke prepare + */ + protected abstract void prepareStatement(String sql, long time); + + /** + * Invoked when prepareCall has been called and completed. + * @param sql - the string used to prepare the statement with + * @param time - the time it took to invoke prepare + */ + protected abstract void prepareCall(String query, long time); + + /** + * Invoked when a query execution, a call to execute/executeQuery or executeBatch failed. + * @param query + * @param args + * @param name + * @param start + * @param t + * @return - the SQL that was executed or the string "batch" + */ + protected String reportFailedQuery(String query, Object[] args, final String name, long start, Throwable t) { + //extract the query string + String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query; + //if we do batch execution, then we name the query 'batch' + if (sql==null && compare(executes[3],name)) { + sql = "batch"; + } + return sql; + } + + /** + * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded but was below the threshold + * @param query + * @param args + * @param name + * @param start + * @param t + * @return - the SQL that was executed or the string "batch" + */ + protected String reportQuery(String query, Object[] args, final String name, long start, long delta) { + //extract the query string + String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query; + //if we do batch execution, then we name the query 'batch' + if (sql==null && compare(executes[3],name)) { + sql = "batch"; + } + return sql; + } + + /** + * Invoked when a query execution, a call to execute/executeQuery or executeBatch succeeded but was above the query time threshold + * @param query + * @param args + * @param name + * @param start + * @param t + * @return - the SQL that was executed or the string "batch" + */ + protected String reportSlowQuery(String query, Object[] args, final String name, long start, long delta) { + //extract the query string + String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query; + //if we do batch execution, then we name the query 'batch' + if (sql==null && compare(executes[3],name)) { + sql = "batch"; + } + return sql; + } + + /** + * returns the query measure threshold. + * This value is in milliseconds. If the query is faster than this threshold than it wont be accounted for + * @return + */ + public long getThreshold() { + return threshold; + } + + /** + * Sets the query measurement threshold. The value is in milliseconds. + * If the query goes faster than this threshold it will not be recorded. + * @param threshold set to -1 to record every query. Value is in milliseconds. + */ + public void setThreshold(long threshold) { + this.threshold = threshold; + } + + /** + * Creates a constructor for a proxy class, if one doesn't already exist + * @param idx - the index of the constructor + * @param clazz - the interface that the proxy will implement + * @return - returns a constructor used to create new instances + * @throws NoSuchMethodException + */ + protected Constructor getConstructor(int idx, Class clazz) throws NoSuchMethodException { + if (constructors[idx]==null) { + Class proxyClass = Proxy.getProxyClass(SlowQueryReport.class.getClassLoader(), new Class[] {clazz}); + constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class }); + } + return constructors[idx]; + } + + /** + * Creates a statement interceptor to monitor query response times + */ + @Override + public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) { + try { + Object result = null; + String name = method.getName(); + String sql = null; + Constructor constructor = null; + if (compare(statements[0],name)) { + //createStatement + constructor = getConstructor(0,Statement.class); + }else if (compare(statements[1],name)) { + //prepareStatement + sql = (String)args[0]; + constructor = getConstructor(1,PreparedStatement.class); + if (sql!=null) { + prepareStatement(sql, time); + } + }else if (compare(statements[2],name)) { + //prepareCall + sql = (String)args[0]; + constructor = getConstructor(2,CallableStatement.class); + prepareCall(sql,time); + }else { + //do nothing, might be a future unsupported method + //so we better bail out and let the system continue + return statement; + } + result = constructor.newInstance(new Object[] { new StatementProxy(statement,sql) }); + return result; + }catch (Exception x) { + log.warn("Unable to create statement proxy for slow query report.",x); + } + return statement; + } + + + /** + * Class to measure query execute time + * @author fhanik + * + */ + protected class StatementProxy implements InvocationHandler { + protected boolean closed = false; + protected Object delegate; + protected final String query; + public StatementProxy(Object parent, String query) { + this.delegate = parent; + this.query = query; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + //get the name of the method for comparison + final String name = method.getName(); + //was close invoked? + boolean close = compare(JdbcInterceptor.CLOSE_VAL,name); + //allow close to be called multiple times + if (close && closed) return null; + //are we calling isClosed? + if (compare(JdbcInterceptor.ISCLOSED_VAL,name)) return closed; + //if we are calling anything else, bail out + if (closed) throw new SQLException("Statement closed."); + boolean process = false; + //check to see if we are about to execute a query + process = process(executes, method, process); + //if we are executing, get the current time + long start = (process)?System.currentTimeMillis():0; + Object result = null; + try { + //execute the query + result = method.invoke(delegate,args); + }catch (Throwable t) { + reportFailedQuery(query,args,name,start,t); + throw t; + } + //measure the time + long delta = (process)?(System.currentTimeMillis()-start):Long.MIN_VALUE; + //see if we meet the requirements to measure + if (delta>threshold) { + try { + //report the slow query + reportSlowQuery(query, args, name, start, delta); + }catch (Exception t) { + if (log.isWarnEnabled()) log.warn("Unable to process slow query",t); + } + } else { + reportQuery(query, args, name, start, delta); + } + //perform close cleanup + if (close) { + closed=true; + delegate = null; + } + return result; + } + } + +} \ No newline at end of file Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java?rev=729554&r1=729553&r2=729554&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java Fri Dec 26 15:14:13 2008 @@ -46,14 +46,9 @@ * @author Filip Hanik * @version 1.0 */ -public class SlowQueryReport extends AbstractCreateStatementInterceptor { +public class SlowQueryReport extends AbstractQueryReport { //logger protected static Log log = LogFactory.getLog(SlowQueryReport.class); - /** - * the constructors that are used to create statement proxies - */ - protected static final Constructor[] constructors = - new Constructor[AbstractCreateStatementInterceptor.statements.length]; /** * we will be keeping track of query stats on a per pool basis @@ -65,10 +60,6 @@ */ protected ConcurrentHashMap<String,QueryStats> queries = null; /** - * The threshold in milliseconds. If the query is faster than this, we don't measure it - */ - protected long threshold = 1000; //don't report queries less than this - /** * Maximum number of queries we will be storing */ protected int maxQueries= 1000; //don't store more than this amount of queries @@ -89,28 +80,10 @@ super(); } - /** - * returns the query measure threshold. - * This value is in milliseconds. If the query is faster than this threshold than it wont be accounted for - * @return - */ - public long getThreshold() { - return threshold; - } - - /** - * Sets the query measurement threshold. The value is in milliseconds. - * If the query goes faster than this threshold it will not be recorded. - * @param threshold set to -1 to record every query. Value is in milliseconds. - */ - public void setThreshold(long threshold) { - this.threshold = threshold; - } - public void setMaxQueries(int maxQueries) { this.maxQueries = maxQueries; } - + /** * invoked when the connection receives the close request * Not used for now. @@ -120,64 +93,18 @@ queries = null; } - /** - * Creates a constructor for a proxy class, if one doesn't already exist - * @param idx - the index of the constructor - * @param clazz - the interface that the proxy will implement - * @return - returns a constructor used to create new instances - * @throws NoSuchMethodException - */ - protected Constructor getConstructor(int idx, Class clazz) - throws NoSuchMethodException { - if (constructors[idx]==null) { - Class proxyClass = Proxy.getProxyClass(SlowQueryReport.class.getClassLoader(), new Class[] {clazz}); - constructors[idx] = proxyClass.getConstructor(new Class[] { InvocationHandler.class }); - } - return constructors[idx]; + @Override + public void prepareStatement(String sql, long time) { + QueryStats qs = getQueryStats(sql); + qs.prepare(time, System.currentTimeMillis()); } - - /** - * Creates a statement interceptor to monitor query response times - */ + @Override - public Object createStatement(Object proxy, Method method, Object[] args, Object statement, long time) { - try { - Object result = null; - String name = method.getName(); - String sql = null; - Constructor constructor = null; - if (compare(statements[0],name)) { - //createStatement - constructor = getConstructor(0,Statement.class); - }else if (compare(statements[1],name)) { - //prepareStatement - sql = (String)args[0]; - constructor = getConstructor(1,PreparedStatement.class); - if (sql!=null) { - QueryStats qs = getQueryStats(sql); - qs.prepare(time, System.currentTimeMillis()); - } - }else if (compare(statements[2],name)) { - //prepareCall - sql = (String)args[0]; - constructor = getConstructor(2,CallableStatement.class); - if (sql!=null) { - QueryStats qs = getQueryStats(sql); - qs.prepare(time, System.currentTimeMillis()); - } - }else { - //do nothing, might be a future unsupported method - //so we better bail out and let the system continue - return statement; - } - result = constructor.newInstance(new Object[] { new StatementProxy(statement,sql) }); - return result; - }catch (Exception x) { - log.warn("Unable to create statement proxy for slow query report.",x); - } - return statement; + public void prepareCall(String sql, long time) { + QueryStats qs = getQueryStats(sql); + qs.prepare(time, System.currentTimeMillis()); } - + /** * {...@inheritdoc} */ @@ -209,39 +136,6 @@ super.poolClosed(pool); } - protected String reportFailedQuery(String query, Object[] args, final String name, long start, Throwable t) { - //extract the query string - String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query; - //if we do batch execution, then we name the query 'batch' - if (sql==null && compare(executes[3],name)) { - sql = "batch"; - } - //if we have a query, record the stats - if (sql!=null) { - QueryStats qs = getQueryStats(sql); - if (qs!=null) qs.failure(System.currentTimeMillis()-start,start); - if (log.isWarnEnabled()) log.warn("Failed query["+sql+"] Stacktrace:"+ConnectionPool.getStackTrace(t)); - - } - return sql; - } - - protected String reportSlowQuery(String query, Object[] args, final String name, long start, long delta) { - //extract the query string - String sql = (query==null && args!=null && args.length>0)?(String)args[0]:query; - //if we do batch execution, then we name the query 'batch' - if (sql==null && compare(executes[3],name)) { - sql = "batch"; - } - //if we have a query, record the stats - if (sql!=null) { - QueryStats qs = getQueryStats(sql); - if (qs!=null) qs.add(delta,start); - if (log.isWarnEnabled()) log.warn("Slow query["+sql+"] Time to execute:"+delta+" ms."); - } - return sql; - } - protected QueryStats getQueryStats(String sql) { ConcurrentHashMap<String,QueryStats> queries = SlowQueryReport.this.queries; if (queries==null) return null; @@ -497,61 +391,5 @@ } } - /** - * Class to measure query execute time - * @author fhanik - * - */ - protected class StatementProxy implements InvocationHandler { - protected boolean closed = false; - protected Object delegate; - protected final String query; - public StatementProxy(Object parent, String query) { - this.delegate = parent; - this.query = query; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //get the name of the method for comparison - final String name = method.getName(); - //was close invoked? - boolean close = compare(JdbcInterceptor.CLOSE_VAL,name); - //allow close to be called multiple times - if (close && closed) return null; - //are we calling isClosed? - if (compare(JdbcInterceptor.ISCLOSED_VAL,name)) return closed; - //if we are calling anything else, bail out - if (closed) throw new SQLException("Statement closed."); - boolean process = false; - //check to see if we are about to execute a query - process = process(executes, method, process); - //if we are executing, get the current time - long start = (process)?System.currentTimeMillis():0; - Object result = null; - try { - //execute the query - result = method.invoke(delegate,args); - }catch (Throwable t) { - reportFailedQuery(query,args,name,start,t); - throw t; - } - //measure the time - long delta = (process)?(System.currentTimeMillis()-start):Long.MIN_VALUE; - //see if we meet the requirements to measure - if (delta>threshold) { - try { - //report the slow query - reportSlowQuery(query, args, name, start, delta); - }catch (Exception t) { - if (log.isWarnEnabled()) log.warn("Unable to process slow query",t); - } - } - //perform close cleanup - if (close) { - closed=true; - delegate = null; - } - return result; - } - } + } Modified: tomcat/trunk/modules/jdbc-pool/sign.sh URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/sign.sh?rev=729554&r1=729553&r2=729554&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/sign.sh (original) +++ tomcat/trunk/modules/jdbc-pool/sign.sh Fri Dec 26 15:14:13 2008 @@ -1,4 +1,4 @@ -VERSION=v1.0.11-beta +VERSION=v1.0.12-beta for i in $(find output/release/$VERSION -name "*.zip" -o -name "*.tar.gz"); do echo Signing $i echo $1|gpg --passphrase-fd 0 -a -b $i --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org