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.tmatrix;
028:
029: import java.io.Serializable;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.Set;
034:
035: import org.cougaar.core.mts.MessageAddress;
036: import org.cougaar.core.qos.metrics.DecayingHistory;
037: import org.cougaar.util.log.Logger;
038: import org.cougaar.util.log.Logging;
039:
040: /*
041: * Traffic Matrix of TrafficRecords, with accessor methods
042: */
043: public class TrafficMatrix implements Serializable
044:
045: {
046: private HashMap outermatrix;
047:
048: /*
049: * Inner class defining a TrafficRecord - there are two records per agent-pair in
050: * the global traffic matrix, defining traffic flow.
051: * E.g. A1->A2 & A2->A1
052: */
053: public static class TrafficRecord extends DecayingHistory.SnapShot
054: implements Serializable {
055: public double msgCount;
056: public double byteCount;
057:
058: public TrafficRecord() {
059: }
060:
061: // deep copy
062: public TrafficRecord(TrafficRecord record) {
063: this .msgCount = record.msgCount;
064: this .byteCount = record.byteCount;
065: }
066:
067: // pass through methods
068: public double getMsgCount() {
069: return msgCount;
070: }
071:
072: public double getByteCount() {
073: return byteCount;
074: }
075:
076: public String toString() {
077: return "Traffic Record: msg=" + msgCount + " bytes="
078: + byteCount;
079: }
080:
081: public TrafficRecord ratifyRecord(TrafficRecord newR) {
082: TrafficRecord result = new TrafficRecord();
083:
084: double deltaTime = (newR.timestamp - timestamp) / 1000.0;
085: if (deltaTime == 0.0) {
086: return null;
087: }
088:
089: double msgCount = newR.getMsgCount() - getMsgCount();
090: double msgRate = msgCount / deltaTime;
091: result.msgCount = msgRate;
092:
093: double byteCount = newR.getByteCount() - getByteCount();
094: double byteRate = byteCount / deltaTime;
095: result.byteCount = byteRate;
096: return result;
097: }
098:
099: } //TrafficRecord
100:
101: /* construct new traffic matrix -
102: * outer = agent to agent
103: * inner = Agent1 to Record1, Record2, Record3,...etc, Agent2 to Record2,...etc.
104: *
105: ---- ----------
106: |A1| ----> |A2|..|..|
107: --- |--|--|--|
108: |A2| |TR|..|..|
109: --- ----------
110: |A3|
111: ---
112:
113: Which essentially looks conceptually like:
114:
115: A1 A2 A3
116:
117: A1 R R R
118:
119: A2 R R R
120:
121: A3 R R R
122:
123: */
124:
125: public TrafficMatrix() {
126: // something extraordinarily large - don't know how many agents we're mapping to
127: this .outermatrix = new HashMap(89);
128: }
129:
130: // Deep copy
131: public TrafficMatrix(TrafficMatrix matrix) {
132: //log.debug("TrafficMatrix passed to constructor: "+matrix);
133: this .outermatrix = new HashMap(89);
134: synchronized (matrix) {
135: Iterator outer = matrix.outermatrix.entrySet().iterator();
136: while (outer.hasNext()) {
137: Map.Entry entry = (Map.Entry) outer.next();
138: MessageAddress orig = (MessageAddress) entry.getKey();
139: HashMap row = (HashMap) entry.getValue();
140: HashMap new_row = new HashMap();
141: this .outermatrix.put(orig, new_row);
142: Iterator inner = row.entrySet().iterator();
143: while (inner.hasNext()) {
144: Map.Entry sub_entry = (Map.Entry) inner.next();
145: MessageAddress target = (MessageAddress) sub_entry
146: .getKey();
147: TrafficRecord data = (TrafficRecord) sub_entry
148: .getValue();
149: new_row.put(target, new TrafficRecord(data));
150: }
151: }
152:
153: }
154: }
155:
156: private transient Logger log;
157:
158: private synchronized Logger getLogger() {
159: if (log == null)
160: log = Logging.getLogger(getClass().getName());
161: return log;
162: }
163:
164: public HashMap getOuter() {
165: return this .outermatrix;
166: }
167:
168: public Set getKeySet() {
169: return outermatrix.keySet();
170: }
171:
172: public void addMsgCount(MessageAddress orig, MessageAddress target,
173: int msgCount) {
174: TrafficRecord record = getOrMakeRecord(orig, target);
175: record.msgCount += msgCount;
176: }
177:
178: public void addByteCount(MessageAddress orig,
179: MessageAddress target, int byteCount) {
180: TrafficRecord record = getOrMakeRecord(orig, target);
181: record.byteCount += byteCount;
182: }
183:
184: /*
185: * Just like getOrMakeRecord, but returns false if either record, orig, or target is null
186: */
187: public boolean checkForRecord(MessageAddress orig_param,
188: MessageAddress target_param) {
189: if (orig_param == null || target_param == null) {
190: return false;
191: }
192: // else check for both present source & target
193: Logger log = getLogger();
194: if (log != null && log.isDebugEnabled()) {
195: log.debug("checkForRecord: orig_param=" + orig_param
196: + ", target_param=" + target_param);
197: }
198: MessageAddress orig = orig_param.getPrimary();
199: MessageAddress target = target_param.getPrimary();
200: HashMap inner = null;
201:
202: // hash to record
203: if (outermatrix.containsKey(orig)) { // has orig
204: inner = (HashMap) outermatrix.get(orig); // get the inner
205: } else {
206: return false;
207: }
208:
209: if (inner.containsKey(target)) { // has target
210: return true;
211: } else { // no inner or record
212: return false;
213: }
214: }
215:
216: public synchronized TrafficRecord getOrMakeRecord(
217: MessageAddress orig_param, MessageAddress target_param) {
218: MessageAddress orig = orig_param.getPrimary();
219: MessageAddress target = target_param.getPrimary();
220: TrafficRecord record = null;
221: HashMap inner = null;
222:
223: // hash to record
224: if (outermatrix.containsKey(orig)) { // has orig
225: inner = (HashMap) outermatrix.get(orig); // get the inner
226: } else {
227: inner = new HashMap();
228: outermatrix.put(orig, inner);
229: }
230:
231: if (inner.containsKey(target)) { // has target
232: record = (TrafficRecord) inner.get(target);
233: } else { // no inner or record
234: record = new TrafficRecord();
235: inner.put(target, record);
236: }
237:
238: return record;
239: }
240:
241: public synchronized TrafficRecord getRecord(
242: MessageAddress orig_param, MessageAddress target_param) {
243: MessageAddress orig = orig_param.getPrimary();
244: MessageAddress target = target_param.getPrimary();
245: HashMap inner = null;
246:
247: // return record if present
248:
249: if (!outermatrix.containsKey(orig))
250: return null; // not present
251:
252: inner = (HashMap) outermatrix.get(orig); // get the inner
253: return (TrafficRecord) inner.get(target);
254: }
255:
256: public synchronized void putRecord(MessageAddress orig_param,
257: MessageAddress target_param, TrafficRecord record) {
258:
259: if (orig_param != null && target_param != null) {
260: MessageAddress orig = orig_param.getPrimary();
261: MessageAddress target = target_param.getPrimary();
262: // should check for existing key, later
263: if (outermatrix.get(orig_param) != null) {
264: HashMap inner = (HashMap) outermatrix.get(orig_param);
265: inner.put(target_param, record);
266: } else {
267: HashMap new_inner = new HashMap(1);
268: new_inner.put(target, record);
269: outermatrix.put(orig, new_inner);
270: }
271: } else {
272: throw new NullPointerException(
273: "Cannot put in TrafficRecord, either Originator or Target is null");
274: }
275: }
276:
277: public TrafficIterator getIterator() {
278: return new TrafficIterator();
279: }
280:
281: /*
282: * Iterator for Traffic Matrix
283: */
284: public class TrafficIterator implements Iterator {
285:
286: private Iterator inner_i, outer_i;
287: private Map.Entry next_inner_entry, next_outer_entry; // look-ahead
288: public MessageAddress inner_key, outer_key; // made public for snapshotMatrix()
289:
290: TrafficIterator() {
291: outer_i = outermatrix.entrySet().iterator();
292: getNextInnerIterator();
293: getNext();
294: }
295:
296: private void getNextInnerIterator() {
297: if (outer_i.hasNext()) {
298: next_outer_entry = (Map.Entry) outer_i.next();
299: HashMap inner = (HashMap) next_outer_entry.getValue();
300: inner_i = inner.entrySet().iterator();
301: } else {
302: inner_i = null;
303: }
304: }
305:
306: private void getNext() {
307: if (inner_i == null) {
308: next_inner_entry = null;
309: } else if (inner_i.hasNext()) {
310: next_inner_entry = (Map.Entry) inner_i.next();
311: } else {
312: getNextInnerIterator();
313: getNext();
314: }
315: }
316:
317: public void remove() {
318: throw new RuntimeException(
319: "TrafficIterator does not support remove()");
320: }
321:
322: public MessageAddress getOrig() {
323: return outer_key;
324: }
325:
326: public MessageAddress getTarget() {
327: return inner_key;
328: }
329:
330: public boolean hasNext() {
331: return next_inner_entry != null;
332: }
333:
334: public Object next() {
335: Object result = null;
336: if (next_inner_entry != null) {
337: outer_key = (MessageAddress) next_outer_entry.getKey();
338: inner_key = (MessageAddress) next_inner_entry.getKey();
339: result = next_inner_entry.getValue();
340: getNext();
341: } else {
342: inner_key = null;
343: outer_key = null;
344: }
345: return result;
346: }
347:
348: }
349:
350: // more utility methods here
351: /*
352: * Run through new matrix, merge into main one
353: */
354: public void addMatrix(TrafficMatrix matrix) {
355: synchronized (outermatrix) {
356: Iterator outer = matrix.outermatrix.entrySet().iterator();
357: while (outer.hasNext()) {
358: Map.Entry entry = (Map.Entry) outer.next();
359: MessageAddress orig = (MessageAddress) entry.getKey();
360: HashMap row = (HashMap) entry.getValue();
361: Iterator inner = row.entrySet().iterator();
362: while (inner.hasNext()) {
363: Map.Entry sub_entry = (Map.Entry) inner.next();
364: MessageAddress target = (MessageAddress) sub_entry
365: .getKey();
366: TrafficRecord data = (TrafficRecord) sub_entry
367: .getValue();
368: putRecord(orig, target, data);
369: }
370: }
371: }
372: }
373:
374: /*
375: * Easy access methods for getting record information
376: * These can return null
377: */
378: public double getByteCount(MessageAddress A1, MessageAddress A2) {
379: TrafficRecord record = getRecord(A1, A2);
380: if (record != null)
381: return record.getByteCount();
382: else
383: return -1.0;
384: }
385:
386: public double getMsgCount(MessageAddress A1, MessageAddress A2) {
387: TrafficRecord record = getRecord(A1, A2);
388: if (record != null)
389: return record.getMsgCount();
390: else
391: return -1.0;
392: }
393:
394: public String toString() {
395: return prettyString("");
396: }
397:
398: public String toPrettyString() {
399: return prettyString("\n");
400: }
401:
402: private String prettyString(String lineBreak) {
403:
404: TrafficIterator itr = this .getIterator();
405: StringBuffer s = new StringBuffer();
406:
407: s.append("TrafficMatrix:");
408: s.append(lineBreak);
409: TrafficRecord record;
410: String orig;
411: String target;
412:
413: while (itr.hasNext()) {
414: record = (TrafficRecord) itr.next();
415: orig = itr.getOrig().toString();
416: target = itr.getTarget().toString();
417: s.append("org=");
418: s.append(orig);
419: ;
420: s.append(" trg=");
421: s.append(target);
422: s.append(" ");
423: s.append(record);
424: s.append(lineBreak);
425: }
426: return s.toString();
427: }
428:
429: public TrafficMatrix ratify(TrafficMatrix newMatrix) {
430: TrafficMatrix result = new TrafficMatrix();
431: ratifyIncremental(newMatrix, result);
432: return result;
433: }
434:
435: public void ratifyIncremental(TrafficMatrix newMatrix,
436: TrafficMatrix result) {
437: Logger log = getLogger();
438: if (log.isDebugEnabled())
439: log.debug("New Matrix" + newMatrix.toPrettyString()
440: + "last Matrix" + toPrettyString());
441: TrafficMatrix.TrafficIterator iter = newMatrix.getIterator();
442: while (iter.hasNext()) {
443: TrafficMatrix.TrafficRecord newRecord = (TrafficMatrix.TrafficRecord) iter
444: .next();
445: MessageAddress orig = iter.getOrig();
446: MessageAddress target = iter.getTarget();
447: // if no entry in old matrix
448: if (!checkForRecord(orig, target)) {
449: // skip this entry
450: continue;
451: } else {
452: TrafficMatrix.TrafficRecord oldRecord = getOrMakeRecord(
453: orig, target);
454: TrafficMatrix.TrafficRecord rateRecord = oldRecord
455: .ratifyRecord(newRecord);
456: if (rateRecord != null) {
457: result.putRecord(orig, target, rateRecord);
458: if (log.isDebugEnabled()) {
459: log.debug("Putting rateRecord: " + orig + ", "
460: + target + ": " + rateRecord);
461: }
462: }
463: }
464: }
465: }
466:
467: } // TrafficMatrix
|