/*
* Copyright (C) 2003-2010 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* 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, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.services.jcr.statistics;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong;
/**
* The class used to manage all the metrics such as minimum, maximum, total, times and average.
*
* Created by The eXo Platform SAS
* Author : Nicolas Filotto
* nicolas.filotto@exoplatform.com
* 30 mars 2010
*/
public class Statistics
{
/**
* The global statistics on the top of the current ones
*/
private final Statistics parent;
/**
* The description of the statistics
*/
private final String description;
/**
* The min value of the time spent for one call
*/
private final AtomicLong min = new AtomicLong(Long.MAX_VALUE);
/**
* The max value of the time spent for one call
*/
private final AtomicLong max = new AtomicLong(-1);
/**
* The total time spent for all the calls
*/
private final AtomicLong total = new AtomicLong();
/**
* The total amount of calls
*/
private final AtomicLong times = new AtomicLong();
/**
* The {@link ThreadLocal} used to keep the initial timestamp
*/
private final ThreadLocal<Queue<Long>> currentTime = new ThreadLocal<Queue<Long>>()
{
protected Queue<Long> initialValue()
{
return new LinkedList<Long>();
}
};
/**
* The default constructor
* @param parent the global statistics on the top of the current ones
* @param description the description of the statistics, to be compatible with the CSV format
* all ',' will be replaced with ';'
*/
public Statistics(Statistics parent, String description)
{
this.parent = parent;
this.description = description.replace(',', ';');
}
/**
* Start recording
*/
public void begin()
{
if (parent != null)
{
parent.onBegin();
}
onBegin();
}
/**
* Store the current timestamp in the {@link ThreadLocal}
*/
private void onBegin()
{
Queue<Long> q = currentTime.get();
q.add(System.currentTimeMillis());
}
/**
* Stop recording
*/
public void end()
{
onEnd();
if (parent != null)
{
parent.onEnd();
}
}
/**
* Refresh the values of the metrics (min, max, total and times)
*/
private void onEnd()
{
long result = System.currentTimeMillis() - currentTime.get().poll();
times.incrementAndGet();
if (result < min.get())
{
min.set(result);
}
if (max.get() < result)
{
max.set(result);
}
total.addAndGet(result);
}
/**
* Print the description of all the metrics into the given {@link PrintWriter}
*/
public void printHeader(PrintWriter pw)
{
pw.print(description);
pw.print("-Min,");
pw.print(description);
pw.print("-Max,");
pw.print(description);
pw.print("-Total,");
pw.print(description);
pw.print("-Avg,");
pw.print(description);
pw.print("-Times");
}
/**
* Print the current snapshot of the metrics and evaluate the average value
*/
public void printData(PrintWriter pw)
{
long lmin = min.get();
if (lmin == Long.MAX_VALUE)
{
lmin = -1;
}
long lmax = max.get();
long ltotal = total.get();
long ltimes = times.get();
float favg = ltimes == 0 ? 0f : (float)ltotal / ltimes;
pw.print(lmin);
pw.print(',');
pw.print(lmax);
pw.print(',');
pw.print(ltotal);
pw.print(',');
pw.print(favg);
pw.print(',');
pw.print(ltimes);
}
/**
* @return The min value of the time spent for one call
*/
public long getMin()
{
long lmin = min.get();
if (lmin == Long.MAX_VALUE)
{
lmin = -1;
}
return lmin;
}
/**
* @return The max value of the time spent for one call
*/
public long getMax()
{
return max.get();
}
/**
* @return The total time spent for all the calls
*/
public long getTotal()
{
return total.get();
}
/**
* @return The total amount of calls
*/
public long getTimes()
{
return times.get();
}
/**
* @return The average time spent for one call
*/
public float getAvg()
{
long ltotal = total.get();
long ltimes = times.get();
float favg = ltimes == 0 ? 0f : (float)ltotal / ltimes;
return favg;
}
/**
* Reset the statistics
*/
public void reset()
{
min.set(Long.MAX_VALUE);
max.set(0);
total.set(0);
times.set(0);
}
}