/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.util;
import java.lang.management.ManagementFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import javax.management.MBeanServer;
import javax.persistence.EntityManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.stat.Statistics;
import org.rhq.core.domain.server.PersistenceUtility;
/**
* @author Joseph Marques
*/
public class HibernatePerformanceMonitor {
private static final Log log = LogFactory.getLog(HibernatePerformanceMonitor.class);
private ConcurrentMap<Long, HibernateStatisticsStopWatch> watches;
private static HibernatePerformanceMonitor singleton = new HibernatePerformanceMonitor();
private AtomicLong idGenerator = new AtomicLong(0);
private HibernatePerformanceMonitor() {
watches = new ConcurrentHashMap<Long, HibernateStatisticsStopWatch>();
}
public static HibernatePerformanceMonitor get() {
return singleton;
}
public static boolean isLoggingEnabled() {
return log.isDebugEnabled();
}
public void zeroStats() {
if (isLoggingEnabled()) {
EntityManager entityManager = LookupUtil.getEntityManager();
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
Statistics stats = PersistenceUtility.getStatisticsService(entityManager, platformMBeanServer);
stats.clear();
}
}
public long start() {
if (isLoggingEnabled()) {
EntityManager entityManager = LookupUtil.getEntityManager();
HibernateStatisticsStopWatch watch = new HibernateStatisticsStopWatch(entityManager);
long id = idGenerator.incrementAndGet();
watches.put(id, watch);
watch.start();
return id;
}
return 0;
}
public void stop(long id, String logPrefix) {
if (isLoggingEnabled()) {
HibernateStatisticsStopWatch watch = watches.remove(id);
if (watch == null) {
return; // could happen if debugging was turned on and the start() call was already skipped
}
watch.stop();
String cause = "";
if (watch.getQueryExecutions() != 0) {
if ((watch.getConnects() / (double) (watch.getEntityLoads() + watch.getQueryExecutions())) >= 5.0) {
cause = "(perf: N+1 issue?) ";// might indicate need for LEFT JOIN FETCHes
}
if ((watch.getTransations() / (double) watch.getQueryExecutions()) >= 5.0) {
cause = "(perf: xaction nesting?) "; // might indicate excessive @REQUIRES_NEW
} else if (watch.getTransations() > 10) {
cause = "(perf: too many xactions?)";
}
}
if (watch.getTime() > 3000) {
cause = "(perf: slowness?) "; // might indicate inefficient query or table contention
}
String callingContext = " for " + (logPrefix == null ? "(unknown)" : logPrefix);
log.debug(watch.toString() + cause + callingContext);
/* these queries are global, not per transaction
if (logPrefix != null && (logPrefix.contains("URL") || logPrefix.contains("GWT:"))) {
String[] queries = watch.getStats().getQueries();
for (int i = 0; i < queries.length; i++) {
String query = queries[i];
QueryStatistics queryStats = watch.getStats().getQueryStatistics(query);
log.debug("query[" + i + "] " + queryStats);
log.debug("query[" + i + "] " + queries[i].replaceAll("\\s+", " "));
}
}
*/
}
}
}