User: juhalindfors Date: 01/04/22 05:56:27 Modified: src/org/jboss/admin/monitor/graph InvocationTimeGraphModel.java Log: txMap will no longer grow indefinately. Handle clock granularity problem with WinNT (<10ms) Handle aggregated invocations correctly (fixes a bug with total invocation count displaying wrong values). Revision Changes Path 1.4 +115 -16 admin/src/org/jboss/admin/monitor/graph/InvocationTimeGraphModel.java Index: InvocationTimeGraphModel.java =================================================================== RCS file: /cvsroot/jboss/admin/src/org/jboss/admin/monitor/graph/InvocationTimeGraphModel.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- InvocationTimeGraphModel.java 2001/04/16 21:55:20 1.3 +++ InvocationTimeGraphModel.java 2001/04/22 12:56:27 1.4 @@ -7,9 +7,13 @@ import java.util.Collection; import java.util.HashMap; import java.util.ArrayList; +import javax.swing.SwingUtilities; // non-standard class dependencies import org.jboss.admin.dataholder.InvocationEntry; +import org.jboss.admin.monitor.event.GraphModelListener; +import org.jboss.admin.monitor.event.GraphModelEvent; +import org.jboss.admin.monitor.event.AggregatedInvocationEvent; import org.gjt.lindfors.util.BoundBuffer; @@ -18,8 +22,8 @@ * * @author <a href="mailto:[EMAIL PROTECTED]">Juha Lindfors</a> */ -public class InvocationTimeGraphModel extends DefaultGraphModel - implements Runnable { +public class InvocationTimeGraphModel extends DefaultGraphModel + implements Runnable { public final static int CONTINUOUS_UPDATE = 0x1; @@ -33,13 +37,16 @@ private Map txMap = Collections.synchronizedMap(new HashMap()); private List resultList = Collections.synchronizedList(new ArrayList()); - protected Collection xAxis = new BoundBuffer(1000); - private int mode = CONTINUOUS_UPDATE; private Thread updateThread = null; private boolean running = true; + private int aggregateCount = 0; + private double aggregateSum = 0; + + private Object lock = new Object(); + /* ************************************************************************* * @@ -99,7 +106,7 @@ } else { - Object value = txMap.get(txID); + Object value = txMap.remove(txID); if (value == null) { System.out.println("Hmm... this end point didnt have a pair: " + txID); @@ -108,13 +115,18 @@ long start = ((Long)value).longValue(); Long diff = new Long(time-start); - - if (mode == PER_INVOCATION_UPDATE) - append(diff); - else if (mode == CONTINUOUS_UPDATE) + + // deal with clock granularity problem, esp. winnt can't deal + // correctly with anything that runs <10ms. + if (diff.longValue() == 0) + diff = new Long(1); + + //if (mode == PER_INVOCATION_UPDATE) + // append(diff); + //else if (mode == CONTINUOUS_UPDATE) resultList.add(diff); - else - throw new InternalError("Unknown mode: " + mode); + //else + // throw new InternalError("Unknown mode: " + mode); } } @@ -145,8 +157,67 @@ public void stopContinuousUpdate() { running = false; updateThread.interrupt(); + } + +/* + ************************************************************************* + * + * METHOD OVERRIDES + * + ************************************************************************* + */ + + /* + * Override the append to call our version of the fireValueAppended() + * [TODO] this version is not thread safe + */ + public void append(Number number) { + xAxis.add(number); + + double avgValue = number.doubleValue(); + + if (avgValue > getVerticalMax()) + setVerticalMax(avgValue); + + int count = 0; + double sum = 0.0; + + // store the aggregate values set by the update thread + // and release the thread from the wait status + synchronized(lock) { + count = aggregateCount; + sum = aggregateSum; + + aggregateCount = 0; + aggregateSum = 0.0; + + lock.notify(); + } + + fireValueAppended(avgValue, sum, count); + } + + /* + * + */ + protected void fireValueAppended(double avgValue, double sum, int count) { + + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length-2; i >= 0; i -= 2) { + + if (listeners[i] == GraphModelListener.class) { + + GraphModelEvent evt = new AggregatedInvocationEvent(this, avgValue, sum, count); + + ((GraphModelListener)listeners[i+1]).valueAppended(evt); + } + } } - + /* ************************************************************************* * @@ -180,10 +251,13 @@ Object[] results = null; + // lock the result list for atomic copy + clear synchronized (resultList) { - if (resultList.size() == 0) - resultList.add(new Long(0)); + if (resultList.size() == 0) { + super.append(new Long(0)); // generates non-aggregated event + return; + } results = resultList.toArray(); resultList.clear(); @@ -193,8 +267,33 @@ for (int i = 0; i < results.length; ++i) sum += ((Long)results[i]).longValue(); - - append(new Long(sum / results.length)); + + synchronized(lock) { + // store the aggregate invocation size for event dispatch thread + aggregateCount = results.length; + aggregateSum = sum; + + final Long average = new Long(sum / results.length); + + // ask the event dispatcher to add the new value to the model and + // fire the required events + SwingUtilities.invokeLater(new Runnable() { + public void run() { + + // this is our overridden version of append + append(average); + } + }); + + // the event dispatcher thread will set this value to zero + // once it has stored it for use in fireValueAppended() method + while (aggregateCount != 0) { + try { + lock.wait(); + } + catch (InterruptedException e) {} + } + } } private String getModeAsString(int mode) { _______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] http://lists.sourceforge.net/lists/listinfo/jboss-development