package org.marketcetera.metrics;
import org.marketcetera.util.misc.ClassVersion;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.Queue;
import java.util.Iterator;
/**
* Instances of this class keep track of per thread metrics. Following metrics
* are kept track of.
* <ol>
* <li>Current: The metrics for the current iteration of the thread.</li>
* <li>Saved: The metrics saved from the previous iterations of the thread.</li>
* <li>Iterations: Total number of iterations.</li>
* </ol>
* <p>
* The {@link ThreadedMetric} class keeps an instance of this class for
* every thread being instrumented.
* <p>
* Here is the object graph that is maintained to keep track of all
* instrumentation metrics
* <ul>
* <li>{@link ThreadedMetric} keeps track of an instance of
* {@link PerThreadInfo} for each thread.</li>
* <ul>
* <li>{@link PerThreadInfo} keeps track of saved and current iteration
* info for each thread and it's total/cumulative iteration count.</li>
* <ul>
* <li>{@link IterationInfo} keeps track of the checkpoints within
* an iteration. It also keeps track of cumulative iteration count until
* the current iteration.</li>
* <ul>
* <li>{@link CheckpointInfo} keeps track of a checkpoint.</li>
* </ul>
* </ul>
* </ul>
* </ul>
*
* <p>
* The contents of this class and other info classes are only updated from
* a single thread: the thread being instrumented. The contents are however
* eventually read by a different thread when summarizing. The data structures
* used should guarantee that the reads from a different thread generate
* consistent & correct results.
*
* @author anshul@marketcetera.com
* @version $Id: PerThreadInfo.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: PerThreadInfo.java 16154 2012-07-14 16:34:05Z colin $")
final class PerThreadInfo implements Iterable<IterationInfo> {
/**
* Adds the supplied checkpoint info to the current iteration info.
*
* @param inInfo the checkpoint info to add.
*/
public void addCurrent(CheckpointInfo inInfo) {
mCurrent.addCheckpoint(inInfo);
}
/**
* Clears the current iteration info. Resets it for the next
* iteration.
*/
public void clearCurrent() {
mCurrent.clear();
}
/**
* Saves off the current iteration info for reporting.
* Resets the current metric for the next iteration.
*/
public void saveCurrent() {
mCurrent.setNumIterations(getIterations());
mSaved.add(mCurrent);
mCurrent = new IterationInfo();
}
/**
* Increments the total/cumulative number of iterations.
*/
public void addIteration() {
mIterations.incrementAndGet();
}
/**
* Returns the total/cumulative number of iterations.
*
* @return the total/cumulative number of iterations.
*/
private long getIterations() {
return mIterations.get();
}
/**
* Clears the saved iteration infos. Resets the state to what it
* was when the instance was initialized.
*/
public void clearSaved() {
mSaved.clear();
mIterations.set(0);
}
/**
* Returns true if there are no saved iteration infos available.
*
* @return true, if there are no saved iteration infos available.
*/
public boolean isSavedEmpty() {
return mSaved.isEmpty();
}
/**
* Returns an iterator that iterates through all the saved metrics.
*
* @return the iterator to iterate through saved metrics.
*/
public Iterator<IterationInfo> iterator() {
return mSaved.iterator();
}
/**
* Returns the name of the thread for which this metric has been collected.
*
* @return the name of the thread.
*/
public String getName() {
return mName;
}
/**
* Creates an empty instance.
*/
PerThreadInfo() {
}
/**
* The current iteration info. ie. the iteration that's currently in
* progress. Need not be volatile, as it's always written to & read from
* the same thread.
*/
private IterationInfo mCurrent = new IterationInfo();
/**
* The iteration counter.
*/
private final AtomicLong mIterations = new AtomicLong();
/**
* The name of the thread being instrumented.
*/
private final String mName = Thread.currentThread().getName();
/**
* The list of saved iteration infos. This list is written to from
* the thread being instrumented and the thread invoking
* {@link #clearSaved()}. It's read when summarizing the metrics.
*/
private final Queue<IterationInfo> mSaved = new ConcurrentLinkedQueue<IterationInfo>();
}