001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.qos.metrics;
028:
029: import java.util.HashMap;
030: import java.util.LinkedList;
031:
032: /**
033: * This helper class is used to keep a history of sensor values and
034: * process them into metrics representing rates. The snapshots of
035: * the sensor values are kept in a series of cascading stores thats
036: * systematically discard the data as it gets older. Instantiable
037: * extensions must implement the {@link #newAddition newAddition}, which is
038: * called when a snapshot is added or when its propagate to the next
039: * level in the cascade.
040: */
041: public abstract class DecayingHistory implements Constants {
042:
043: /**
044: * Callback with a pair of snapshots that need to be processed.
045: * The KeyMap holds the key string the averaging period for this
046: * pair.
047: */
048: public abstract void newAddition(KeyMap keys, SnapShot now,
049: SnapShot last);
050:
051: /**
052: * These are snapshots as stored in history. The abstract class
053: * only stores timestamps. Extend this class to store the
054: * accumulators values
055: */
056: public static class SnapShot {
057: public long timestamp;
058:
059: public SnapShot() {
060: timestamp = System.currentTimeMillis();
061: }
062: }
063:
064: private int basePeriod;
065: private KeyMap baseKeys;
066: private int rows;
067:
068: // Convert column to the 1xxxSecAvg String
069: // Columns start a 1, base is 0
070: private String columnToSecavg(int column) {
071: long periodInt = basePeriod
072: * Math.round(Math.pow(rows, column));
073: return periodInt + SecAvgKeySuffix;
074: }
075:
076: /**
077: * Keeps a map of interned strings Each 1xxxSecAvg will have its
078: * own map. The customer of DecayingHistory will supply the key
079: * prefix and full key will be stored in map.
080: */
081: public class KeyMap {
082: private String suffix;
083: HashMap map = new HashMap();
084:
085: KeyMap(String suffix) {
086: super ();
087: this .suffix = suffix;
088: }
089:
090: public void addKey(String prefix) {
091: String full = prefix + suffix;
092: map.put(prefix.intern(), full.intern());
093: }
094:
095: public String getKey(String prefix) {
096: return (String) map.get(prefix);
097: }
098:
099: public String getAvgPeriod() {
100: return suffix;
101: }
102: }
103:
104: // The column data structure,
105: // Keep a history and pass on the now-snapshot to the next column
106: // after "length" number of elements have been added
107: private class DecayingHistoryList extends LinkedList {
108: private int column;
109: private int length;
110: private int index;
111: private boolean full;
112: private KeyMap keys;
113:
114: DecayingHistoryList(int column, int length, int basePeriod) {
115: this .column = column;
116: this .length = length;
117: keys = new KeyMap(columnToSecavg(column + 1));
118: index = 0;
119: full = false;
120: }
121:
122: DecayingHistoryList(int column, int length) {
123: this (column, length, 1);
124: }
125:
126: public void addSnapShot(SnapShot new_elt) {
127: //First Element (No calculation)
128: if (size() == 0) {
129: addFirst(new_elt);
130: DecayingHistoryList next = getList(column + 1);
131: if (next != null)
132: next.addSnapShot(new_elt);
133: return;
134: }
135:
136: // Notify the listener to Calculate Delta between SnapShot
137: SnapShot last = (SnapShot) getLast();
138: newAddition(keys, new_elt, last);
139:
140: // make room, if full
141: if (full)
142: last = (SnapShot) removeLast();
143: // Rember SnapShot
144: addFirst(new_elt);
145:
146: // Time to give element to next history
147: boolean shift = ++index == length;
148: if (shift) {
149: DecayingHistoryList next = getList(column + 1);
150: if (next != null)
151: next.addSnapShot(new_elt);
152: full = true;
153: index = 0;
154: }
155: }
156: }
157:
158: // History for each column/exponent
159: private DecayingHistoryList[] history;
160: private int total_count = 0;
161:
162: public DecayingHistory(int rows, int columns, int basePeriod) {
163: this .rows = rows;
164: this .basePeriod = basePeriod;
165: baseKeys = new KeyMap(columnToSecavg(0));
166: history = new DecayingHistoryList[columns];
167: for (int i = 0; i < history.length; i++) {
168: history[i] = new DecayingHistoryList(i, rows, basePeriod);
169: }
170: }
171:
172: public DecayingHistory(int rows, int columns) {
173: this (rows, columns, 1);
174: }
175:
176: private DecayingHistoryList getList(int index) {
177: if (index < history.length)
178: return history[index];
179: else
180: return null;
181: }
182:
183: public synchronized void addKey(String prefix) {
184: baseKeys.addKey(prefix);
185: for (int i = 0; i < history.length; i++) {
186: history[i].keys.addKey(prefix);
187: }
188: }
189:
190: public synchronized void add(SnapShot new_elt) {
191: // Do Base Period Average
192: if (history[0].size() > 0) {
193: SnapShot last = (SnapShot) history[0].getFirst();
194: newAddition(baseKeys, new_elt, last);
195: }
196: // Added to history
197: history[0].addSnapShot(new_elt);
198: ++total_count;
199: }
200: }
|