package com.bigdata.counters; import org.apache.log4j.Logger; /** * A history instrument which aggregates samples into a circular buffer with a * specified sample period. Old samples are overwritten (or cleared in the case * of missed samples) only as new samples arrive. The value reported for a given * moment is the average of the samples which were aggregated into the same slot * in the underlying {@link History}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ * * @param <T> * Which must be Double, Long, or String. */ public class HistoryInstrument<T> implements IInstrument<T> { protected static Logger log = Logger.getLogger(HistoryInstrument.class); public final History<T> minutes; public final History<T> hours; public final History<T> days; /** * Return the history data. */ public History<T> getHistory() { return minutes; } /** * Return the {@link History} for the specified base period. * * @param basePeriod * The base period. * * @return The history having samples with that base period. */ public History<T> getHistory(PeriodEnum basePeriod) { switch (basePeriod) { case Minutes: return minutes; case Hours: return hours; case Days: return days; default: throw new AssertionError(); } } public HistoryInstrument(final History<T> minutes) { if (minutes == null) throw new IllegalArgumentException(); this.minutes = minutes; if (minutes.getSink() != null) { hours = minutes.getSink(); if (hours.getSink() != null) { days = hours.getSink(); } else { // no overflow. days = null; } } else { // no overflow. hours = days = null; } } // /** // * // * @param minutes // * An array of the desired data type. If the array does not have // * 60 elements then a new array of the same type will be created. // * Regardless, the array will be used to store one sample per // * minute. // */ // @SuppressWarnings("unchecked") // public HistoryInstrument(T[] minutes) { // // if (minutes == null) // throw new IllegalArgumentException(); // // if (minutes.length != 60) { // // minutes = (T[]) java.lang.reflect.Array.newInstance(minutes // .getClass().getComponentType(), 60); // // } // // /* // * Note: The base period is one minute in milliseconds // */ // this.minutes = new History<T>(minutes, PeriodEnum.Minutes // .getPeriodMillis()); // // // 24 hours in a day // this.hours = new History<T>(24, this.minutes); // // // 30 days of history // this.days = new History<T>(30, this.hours); // // } /** * Return the last value. */ public T getValue() { final IHistoryEntry<T> sample = minutes.getSample(); if (sample == null) return null; return sample.getValue(); } /** * Return the timestamp associated with the last value. */ public long lastModified() { final IHistoryEntry<T> sample = minutes.getSample(); if (sample == null) return -1L; return sample.lastModified(); }; /** * Adds the sample to the history. Samples in the same slot are averaged. * * @param timestamp * The timestamp. * @param value * The value of the counter as of that timestamp. */ public void add(final long timestamp, final T value) { if (log.isInfoEnabled()) log.info("timestamp=" + timestamp + ", value=" + value); minutes.add(timestamp, value); } /** * Adds the sample to the history. Samples in the same slot are averaged. */ public void setValue(final T value, final long timestamp) { add(timestamp, value); } public String toString() { return minutes.toString(); // StringBuilder sb = new StringBuilder(); // // sb.append("history{"); // // sb.append("\nminutes="+minutes); // // sb.append("\nhours="+hours); // // sb.append("\ndays="+days); // // sb.append("\n}"); // // return sb.toString(); } }