package org.limewire.collection;
import java.util.LinkedList;
/**
* Measures the average number of elements in a queueing system.
* <p>
* See <a href="http://en.wikipedia.org/wiki/Little's_law">Little's Law</a> for
* more information.
*
* <pre>
* try{
* QueueCounter qc = new QueueCounter(10);
* System.out.println("Average size: " + qc.getAverageSize());
* for(int i = 0; i < 10; i++){
* qc.recordArrival();
* Thread.sleep( 1000 );
* }
* for(int i = 0; i < 10; i++)
* qc.recordDeparture();
* System.out.println("Average size: " + qc.getAverageSize());
* } catch(Exception e) {
* e.printStackTrace();
* }
*
* Output:
* Average size: -1.0
* Average size: 5.500395106845166
* </pre>
*/
public class QueueCounter {
private LinkedList<Long> arrivals;
private NumericBuffer<Long> timesInSystem;
private NumericBuffer<Long> interarrivalTimes;
private long lastArrival;
public QueueCounter(int historySize) {
arrivals = new LinkedList<Long>();
timesInSystem = new NumericBuffer<Long>(historySize);
interarrivalTimes = new NumericBuffer<Long>(historySize);
}
/**
* Record an arrival in the system.
*/
public synchronized void recordArrival() {
long now = System.nanoTime();
if (!arrivals.isEmpty())
interarrivalTimes.add(now - lastArrival);
arrivals.addLast(now);
lastArrival = now;
}
/**
* Record a departure from the system.
*/
public synchronized void recordDeparture() {
timesInSystem.add(System.nanoTime() - arrivals.removeFirst());
}
/**
* @return the average number of elements in the system.
*/
public synchronized double getAverageSize() {
if (timesInSystem.getSize() < timesInSystem.getCapacity())
return -1;
return timesInSystem.average().doubleValue() / interarrivalTimes.average().doubleValue();
}
/**
* @return if the system could be considered stale. More specifically, this
* returns true if all of the following are true:
*
* <pre>
* 1. we have enough historical data and
* 2. the system has been empty for longer than the period over which the
* historical data was recorded.
* </pre>
*
* Note that this is an arbitrary recommendation and may be
* completely irrelevant for some purposes.
*/
public synchronized boolean isStale() {
if (timesInSystem.size() < timesInSystem.getCapacity())
return false;
if (!arrivals.isEmpty())
return false;
return System.nanoTime() - lastArrival > interarrivalTimes.sum().longValue()
+ timesInSystem.last();
}
/**
* Forgets all recorded data.
*/
public synchronized void reset() {
timesInSystem.clear();
interarrivalTimes.clear();
arrivals.clear();
lastArrival = 0;
}
}