📄 profiledconnection.java
字号:
/**
* $RCSfile: ProfiledConnection.java,v $
* $Revision: 1.1.1.1 $
* $Date: 2002/09/09 13:51:02 $
*
* Copyright (C) 2002 CoolServlets, Inc. All rights reserved.
*
* This software is the proprietary information of CoolServlets, Inc.
* Use is subject to license terms.
*/
package com.jivesoftware.forum.database;
import java.sql.*;
import java.util.*;
import com.jivesoftware.util.*;
/**
* Wraps a Connection object and collects statistics about the database queries
* that are performed.<p>
*
* Statistics of the profiled Connections can be obtained from the static
* methods of this class. Instances of this class are the actual wrappers that
* perform profiling.
*/
public class ProfiledConnection extends ConnectionAdapter {
/**
* Constant for SELECT database queries.
*/
public static final int SELECT = 0;
/**
* Constant for UPDATE database queries.
*/
public static final int UPDATE = 1;
/**
* Constant for INSERT database queries.
*/
public static final int INSERT = 2;
/**
* Constant for DELETE database queries.
*/
public static final int DELETE = 3;
private static long startInsertTime = 0;
private static long startUpdateTime = 0;
private static long startSelectTime = 0;
private static long startDeleteTime = 0;
private static long endInsertTime = 0;
private static long endUpdateTime = 0;
private static long endSelectTime = 0;
private static long endDeleteTime = 0;
private static long insertCount = 0;
private static long updateCount = 0;
private static long selectCount = 0;
private static long deleteCount = 0;
private static long totalInsertTime = 0;
private static long totalUpdateTime = 0;
private static long totalSelectTime = 0;
private static long totalDeleteTime = 0;
private static Hashtable insertQueries = new Hashtable();
private static Hashtable updateQueries = new Hashtable();
private static Hashtable selectQueries = new Hashtable();
private static Hashtable deleteQueries = new Hashtable();
/**
* Start profiling.
*/
public static void start() {
long now = System.currentTimeMillis();
startInsertTime = startUpdateTime = startSelectTime = startDeleteTime = now;
}
/**
* Stop profiling.
*/
public static void stop() {
endInsertTime = endUpdateTime = endSelectTime = endDeleteTime = 0;
}
/**
* Returns the total number database queries of a particular type performed.
* Valid types are ProfiledConnection.SELECT, ProfiledConnection.UPDATE,
* ProfiledConnection.INSERT, and ProfiledConnection.DELETE.
*
* @param type the type of query to get the count for.
* @return the number queries of type <tt>type</tt> performed.
*/
public static long getQueryCount(int type) {
switch (type) {
case SELECT:
return selectCount;
case UPDATE:
return updateCount;
case INSERT:
return insertCount;
case DELETE:
return deleteCount;
default:
throw new IllegalArgumentException("Invalid type");
}
}
/**
*
*
* @param sql the insert sql string.
* @param time the length of time the query took in milliseconds
*/
public static void addQuery(int type, String sql, long time) {
// Do nothing if we didn't receive a sql statement
if (sql == null || sql.equals("")) {
return;
}
// clean up sql to insert spaces after every ','
sql = reformatQuery(sql);
// remove values from query
sql = removeQueryValues(sql);
ProfiledConnectionEntry entry = null;
switch (type) {
case SELECT:
selectCount++;
totalSelectTime += time;
entry = (ProfiledConnectionEntry)selectQueries.get(sql);
if (entry == null) {
entry = new ProfiledConnectionEntry(sql);
selectQueries.put(sql, entry);
}
break;
case UPDATE:
updateCount++;
totalUpdateTime += time;
entry = (ProfiledConnectionEntry)updateQueries.get(sql);
if (entry == null) {
entry = new ProfiledConnectionEntry(sql);
updateQueries.put(sql, entry);
}
break;
case INSERT:
insertCount++;
totalInsertTime += time;
entry = (ProfiledConnectionEntry)insertQueries.get(sql);
if (entry == null) {
entry = new ProfiledConnectionEntry(sql);
insertQueries.put(sql, entry);
}
break;
case DELETE:
deleteCount++;
totalDeleteTime += time;
entry = (ProfiledConnectionEntry)deleteQueries.get(sql);
if (entry == null) {
entry = new ProfiledConnectionEntry(sql);
deleteQueries.put(sql, entry);
}
break;
default:
throw new IllegalArgumentException("Invalid type");
}
entry.count++;
entry.totalTime += time;
}
/**
* Returns the average number of queries of a certain type that have been
* performed per second since profiling started. If profiling has been
* stopped, that moment in time is used for the calculation. Otherwise,
* the current moment in time is used.
*
* @param type the type of database query to check.
* @return the average number of queries of a certain typed performed per
* second.
*/
public static double getQueriesPerSecond(int type) {
long count, start, end;
switch (type) {
case SELECT:
count = selectCount;
start = startSelectTime;
end = endSelectTime;
break;
case UPDATE:
count = updateCount;
start = startUpdateTime;
end = endUpdateTime;
break;
case INSERT:
count = insertCount;
start = startInsertTime;
end = endInsertTime;
break;
case DELETE:
count = deleteCount;
start = startDeleteTime;
end = endDeleteTime;
break;
default:
throw new IllegalArgumentException("Invalid type");
}
// if no queries yet, return 0;
if (count == 0) {
return 0;
}
// If the profiling hasn't been stopped yet, we want to give
// profiling values up to the current time instead.
if (end == 0) {
end = System.currentTimeMillis();
}
// Compute the number of seconds
double time = (end - start)/1000.0;
// Finally, return the average.
return count / time;
}
/**
* Returns the average amount of time spent executing the specified type
* of query.
*
* @param type the type of query.
* @return a double representing the average time spent executing the type
* of query.
*/
public static double getAverageQueryTime(int type) {
long time, count;
switch (type) {
case SELECT:
count = selectCount;
time = totalSelectTime;
break;
case UPDATE:
count = updateCount;
time = totalUpdateTime;
break;
case INSERT:
count = insertCount;
time = totalInsertTime;
break;
case DELETE:
count = deleteCount;
time = totalDeleteTime;
break;
default:
throw new IllegalArgumentException("Invalid type");
}
if (count != 0) {
return time/(double)count;
}
else {
return 0.0;
}
}
/**
* Returns the total amount of time in milliseconds spent doing a particular
* type of query. Note that this isn't necessarily representative of actual real
* time since db queries often occur in parallel.
*
* @param type the type of query to check.
* @return the number of milliseconds spent executing the specified type of
* query.
*/
public static long getTotalQueryTime(int type) {
switch (type) {
case SELECT:
return totalSelectTime;
case UPDATE:
return totalUpdateTime;
case INSERT:
return totalInsertTime;
case DELETE:
return totalDeleteTime;
default:
throw new IllegalArgumentException("Invalid type");
}
}
/**
* Returns an array of sorted queries (as ProfiledConnectionEntry objects) by type
*
* @param type the type of query to check
* @param sortByTime sort the resulting list by Time if true,
* otherwise sort by count if false (default)
* @return an array of ProfiledConnectionEntry objects
*/
public static ProfiledConnectionEntry[] getSortedQueries(int type, boolean sortByTime) {
Hashtable queries;
switch (type) {
case SELECT:
queries = selectQueries;
break;
case UPDATE:
queries = updateQueries;
break;
case INSERT:
queries = insertQueries;
break;
case DELETE:
queries = deleteQueries;
break;
default:
throw new IllegalArgumentException("Invalid type");
}
ProfiledConnectionEntry[] result = new ProfiledConnectionEntry[queries.size()];
// no queries, return null set
if (queries.size() < 1) {
return null;
}
// since the values of the hashtable contain everything that
// we need (including the sql statement), ignore the keys
Enumeration e = queries.elements();
int c = 0;
while (e.hasMoreElements()) {
result[c++] = (ProfiledConnectionEntry) e.nextElement();
}
quickSort(result, sortByTime, 0, result.length -1);
return result;
}
/**
* Reset all statistics.
*/
public static void resetStatistics() {
startInsertTime = startUpdateTime = startSelectTime = startDeleteTime = 0;
endInsertTime = endUpdateTime = endSelectTime = endDeleteTime = 0;
insertCount = updateCount = selectCount = deleteCount = 0;
totalInsertTime = totalUpdateTime = totalSelectTime = totalDeleteTime = 0;
insertQueries.clear();
updateQueries.clear();
selectQueries.clear();
deleteQueries.clear();
}
/**
* @param entries entries
* @param sortByTime sort by time if true, otherwise sort by count
* @param first first index to sort on. Normally 0
* @param last last index to sort on. Normally length -1
*/
private static void quickSort(ProfiledConnectionEntry[] entries, boolean sortByTime, int first, int last) {
// do nothing if array contains fewer than two elements
if (first >= last || entries.length < 2) {
return;
}
swap(entries, first, (first+last)/2);
int index = first;
for (int i=first+1; i <= last; i++) {
if (sortByTime && ((entries[first].totalTime/entries[first].count) < (entries[i].totalTime/entries[i].count))) {
swap(entries, ++index, i);
}
else if (!sortByTime && entries[first].count < entries[i].count) {
swap(entries, ++index, i);
}
}
swap(entries, first, index);
quickSort(entries, sortByTime, first, index-1);
quickSort(entries, sortByTime, index+1, last);
}
private static void swap(Object[] list, int i, int j) {
Object tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
private static String removeQueryValues(String _sql) {
int length = _sql.length();
if (_sql.indexOf("=") == -1) {
return _sql;
}
StringBuffer sql = new StringBuffer(_sql);
boolean inValue = false;
boolean afterEquals = false;
boolean hasQuotes = false;
int startValue = -1;
int endValue = -1;
int charRemoved = 0;
for (int x = 0; x < length; x++) {
char c = _sql.charAt(x);
switch (c) {
case '=': {
if (!afterEquals) {
afterEquals = true;
}
break;
}
case ' ': {
if (!hasQuotes && inValue) {
endValue = x;
inValue = false;
hasQuotes = false;
afterEquals = false;
}
break;
}
case '\'': {
if (afterEquals && !inValue) {
startValue = x;
inValue = true;
hasQuotes = true;
}
else if (afterEquals && inValue && hasQuotes) {
endValue = x+1;
inValue = false;
hasQuotes = false;
afterEquals = false;
}
break;
}
case '-': {
if (afterEquals && !inValue) {
startValue = x;
inValue = true;
}
break;
}
case '+': {
if (afterEquals && !inValue) {
startValue = x;
inValue = true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -