/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.stat.internal;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.hibernate.stat.QueryStatistics;
Query statistics (HQL and SQL)
Note that for a cached query, the cache miss is equals to the db count
Author: Alex Snaps
/**
* Query statistics (HQL and SQL)
* <p/>
* Note that for a cached query, the cache miss is equals to the db count
*
* @author Alex Snaps
*/
public class ConcurrentQueryStatisticsImpl extends CategorizedStatistics implements QueryStatistics {
private final AtomicLong cacheHitCount = new AtomicLong();
private final AtomicLong cacheMissCount = new AtomicLong();
private final AtomicLong cachePutCount = new AtomicLong();
private final AtomicLong executionCount = new AtomicLong();
private final AtomicLong executionRowCount = new AtomicLong();
private final AtomicLong executionMaxTime = new AtomicLong();
private final AtomicLong executionMinTime = new AtomicLong(Long.MAX_VALUE);
private final AtomicLong totalExecutionTime = new AtomicLong();
private final Lock readLock;
private final Lock writeLock;
{
ReadWriteLock lock = new ReentrantReadWriteLock();
readLock = lock.readLock();
writeLock = lock.writeLock();
}
ConcurrentQueryStatisticsImpl(String query) {
super(query);
}
queries executed to the DB
/**
* queries executed to the DB
*/
public long getExecutionCount() {
return executionCount.get();
}
Queries retrieved successfully from the cache
/**
* Queries retrieved successfully from the cache
*/
public long getCacheHitCount() {
return cacheHitCount.get();
}
public long getCachePutCount() {
return cachePutCount.get();
}
public long getCacheMissCount() {
return cacheMissCount.get();
}
Number of lines returned by all the executions of this query (from DB) For now, Query.iterate()
and org.hibernate.Query#scroll()()
do not fill this statistic Returns: The number of rows cumulatively returned by the given query; iterate
and scroll queries do not effect this total as their number of returned rows
is not known at execution time.
/**
* Number of lines returned by all the executions of this query (from DB)
* For now, {@link org.hibernate.Query#iterate()}
* and {@link org.hibernate.Query#scroll()()} do not fill this statistic
*
* @return The number of rows cumulatively returned by the given query; iterate
* and scroll queries do not effect this total as their number of returned rows
* is not known at execution time.
*/
public long getExecutionRowCount() {
return executionRowCount.get();
}
average time in ms taken by the excution of this query onto the DB
/**
* average time in ms taken by the excution of this query onto the DB
*/
public long getExecutionAvgTime() {
// We write lock here to be sure that we always calculate the average time
// with all updates from the executed applied: executionCount and totalExecutionTime
// both used in the calculation
writeLock.lock();
try {
long avgExecutionTime = 0;
if (executionCount.get() > 0) {
avgExecutionTime = totalExecutionTime.get() / executionCount.get();
}
return avgExecutionTime;
} finally {
writeLock.unlock();
}
}
max time in ms taken by the excution of this query onto the DB
/**
* max time in ms taken by the excution of this query onto the DB
*/
public long getExecutionMaxTime() {
return executionMaxTime.get();
}
min time in ms taken by the excution of this query onto the DB
/**
* min time in ms taken by the excution of this query onto the DB
*/
public long getExecutionMinTime() {
return executionMinTime.get();
}
add statistics report of a DB query
Params: - rows – rows count returned
- time – time taken
/**
* add statistics report of a DB query
*
* @param rows rows count returned
* @param time time taken
*/
void executed(long rows, long time) {
// read lock is enough, concurrent updates are supported by the underlying type AtomicLong
// this only guards executed(long, long) to be called, when another thread is executing getExecutionAvgTime()
readLock.lock();
try {
// Less chances for a context switch
for (long old = executionMinTime.get(); (time < old) && !executionMinTime.compareAndSet(old, time); old = executionMinTime.get());
for (long old = executionMaxTime.get(); (time > old) && !executionMaxTime.compareAndSet(old, time); old = executionMaxTime.get());
executionCount.getAndIncrement();
executionRowCount.addAndGet(rows);
totalExecutionTime.addAndGet(time);
} finally {
readLock.unlock();
}
}
public String toString() {
return new StringBuilder()
.append("QueryStatistics")
.append("[cacheHitCount=").append(this.cacheHitCount)
.append(",cacheMissCount=").append(this.cacheMissCount)
.append(",cachePutCount=").append(this.cachePutCount)
.append(",executionCount=").append(this.executionCount)
.append(",executionRowCount=").append(this.executionRowCount)
.append(",executionAvgTime=").append(this.getExecutionAvgTime())
.append(",executionMaxTime=").append(this.executionMaxTime)
.append(",executionMinTime=").append(this.executionMinTime)
.append(']')
.toString();
}
void incrementCacheHitCount() {
cacheHitCount.getAndIncrement();
}
void incrementCacheMissCount() {
cacheMissCount.getAndIncrement();
}
void incrementCachePutCount() {
cachePutCount.getAndIncrement();
}
}