001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.stats.counter.sampled;
005:
006: import com.tc.stats.LossyStack;
007: import com.tc.stats.counter.CounterImpl;
008:
009: import java.math.BigDecimal;
010: import java.math.BigInteger;
011: import java.util.TimerTask;
012:
013: /**
014: * A counter that keeps sampled values
015: */
016: public class SampledCounterImpl extends CounterImpl implements
017: SampledCounter {
018: private final LossyStack history;
019: private final boolean resetOnSample;
020: private final TimerTask samplerTask;
021: private TimeStampedCounterValue min;
022: private TimeStampedCounterValue max;
023: private Double average = null;
024:
025: public SampledCounterImpl(SampledCounterConfig config) {
026: super (config.getInitialValue());
027:
028: this .history = new LossyStack(config.getHistorySize());
029: this .resetOnSample = config.isResetOnSample();
030:
031: this .samplerTask = new TimerTask() {
032: public void run() {
033: recordSample();
034: }
035: };
036:
037: recordSample();
038: }
039:
040: public TimeStampedCounterValue getMostRecentSample() {
041: return (TimeStampedCounterValue) this .history.peek();
042: }
043:
044: public TimeStampedCounterValue[] getAllSampleValues() {
045: return (TimeStampedCounterValue[]) this .history
046: .toArray(new TimeStampedCounterValue[this .history
047: .depth()]);
048: }
049:
050: public void shutdown() {
051: if (samplerTask != null) {
052: samplerTask.cancel();
053: }
054: }
055:
056: TimerTask getTimerTask() {
057: return this .samplerTask;
058: }
059:
060: synchronized void recordSample() {
061: final long sample;
062: if (resetOnSample) {
063: sample = getAndSet(0L);
064: } else {
065: sample = getValue();
066: }
067:
068: final long now = System.currentTimeMillis();
069: TimeStampedCounterValue timedSample = new TimeStampedCounterValue(
070: now, sample);
071:
072: if ((min == null) || (sample < min.getCounterValue())) {
073: min = timedSample;
074: }
075:
076: if ((max == null) || (sample > max.getCounterValue())) {
077: max = timedSample;
078: }
079:
080: average = null; // force average to be computed again
081: history.push(timedSample);
082: }
083:
084: public synchronized TimeStampedCounterValue getMin() {
085: return this .min;
086: }
087:
088: public synchronized TimeStampedCounterValue getMax() {
089: return this .max;
090: }
091:
092: public synchronized double getAverage() {
093: if (average == null) {
094: average = new Double(computeAverage());
095: }
096: return this .average.doubleValue();
097: }
098:
099: private double computeAverage() {
100: TimeStampedCounterValue[] all = getAllSampleValues();
101:
102: if (all.length == 0) {
103: return 0D;
104: }
105:
106: BigInteger total = BigInteger.ZERO;
107: for (int i = 0, n = all.length; i < n; i++) {
108: final long sample = all[i].getCounterValue();
109: total = total.add(new BigInteger(String.valueOf(sample)));
110: }
111:
112: return new BigDecimal(total).divide(new BigDecimal(all.length),
113: BigDecimal.ROUND_HALF_UP).doubleValue();
114: }
115: }
|