package com.limegroup.gnutella; import java.io.IOException; import java.io.NotActiveException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Iterator; import com.limegroup.gnutella.util.Buffer; /** * A helper class for implementing the BandwidthTracker interface. For * backwards compatibility, this implements the Serializable interface and marks * some fields transient. However, LimeWire currently only reads but not writes * BandwidthTrackerImpl. */ public class BandwidthTrackerImpl implements Serializable { static final long serialVersionUID = 7694080781117787305L; static final int HISTORY_SIZE=10; /** Keep 10 clicks worth of data, which we can then average to get a more * accurate moving time average. * INVARIANT: snapShots[0]==measuredBandwidth.floatValue() */ transient Buffer /* of Float */ snapShots = new Buffer(HISTORY_SIZE); /** * Number of times we've been bandwidth measured. */ private transient int numMeasures = 0; /** * Overall average throughput */ private transient float averageBandwidth = 0; /** * The cached getMeasuredBandwidth value. */ private transient float cachedBandwidth = 0; long lastTime; int lastAmountRead; /** The most recent measured bandwidth. DO NOT DELETE THIS; it exists * for backwards serialization reasons. */ float measuredBandwidth; /** * Measures the data throughput since the last call to measureBandwidth, * assuming this has read amountRead bytes. This value can be read by * calling getMeasuredBandwidth. * * @param amountRead the cumulative amount read from this, in BYTES. * Should be larger than the argument passed in the last call to * measureBandwidth(..). */ public synchronized void measureBandwidth(int amountRead) { long currentTime=System.currentTimeMillis(); //We always discard the first sample, and any others until after //progress is made. //This prevents sudden bandwidth spikes when resuming //uploads and downloads. Remember that bytes/msec=KB/sec. if (lastAmountRead==0 || currentTime==lastTime) { measuredBandwidth=0.f; } else { measuredBandwidth=(float)(amountRead-lastAmountRead) / (float)(currentTime-lastTime); //Ensure positive! measuredBandwidth=Math.max(measuredBandwidth, 0.f); } lastTime=currentTime; lastAmountRead=amountRead; averageBandwidth = (averageBandwidth*numMeasures + measuredBandwidth) / ++numMeasures; snapShots.add(new Float(measuredBandwidth)); cachedBandwidth = 0; } /** @see BandwidthTracker#getMeasuredBandwidth */ public synchronized float getMeasuredBandwidth() throws InsufficientDataException { if(cachedBandwidth != 0) return cachedBandwidth; int size = snapShots.getSize(); if (size < 3 ) throw new InsufficientDataException(); Iterator iter = snapShots.iterator(); float total = 0; while(iter.hasNext()) { total+= ((Float)iter.next()).floatValue(); } cachedBandwidth = total/size; return cachedBandwidth; } /** * Returns the average overall bandwidth consumed. */ public synchronized float getAverageBandwidth() { if(snapShots.getSize() < 3) return 0f; return averageBandwidth; } private void readObject(ObjectInputStream in) throws IOException { snapShots=new Buffer(HISTORY_SIZE); numMeasures = 0; averageBandwidth = 0; try { in.defaultReadObject(); } catch (ClassNotFoundException e) { throw new IOException("Class not found"); } catch (NotActiveException e) { throw new IOException("Not active"); } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); } }