Author: xor
Date: 2008-10-27 16:38:43 +0000 (Mon, 27 Oct 2008)
New Revision: 23108

Modified:
   trunk/freenet/src/freenet/node/BandwidthUsageHistory.java
Log:
JavaDoc & implementation of all functions I could think of which are necessary 
for implementing the bandwidth graph in fproxy, now it's time to do that. Feel 
free to review as I have not actually run/tested that code yet.

Modified: trunk/freenet/src/freenet/node/BandwidthUsageHistory.java
===================================================================
--- trunk/freenet/src/freenet/node/BandwidthUsageHistory.java   2008-10-27 
13:52:17 UTC (rev 23107)
+++ trunk/freenet/src/freenet/node/BandwidthUsageHistory.java   2008-10-27 
16:38:43 UTC (rev 23108)
@@ -1,35 +1,31 @@
 package freenet.node;

 import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Date;
 import java.util.NoSuchElementException;

 /**
- * A fixed-size list of bandwidth usage measurements. Storing a measurement
- * automatically stores the time when it was added.
+ * A fixed-size list of bandwidth usage measurements.
  * 
  * @author xor
  * 
  */
-public class BandwidthUsageHistory implements
-               Iterable<BandwidthUsageHistory.BandwidthUsageSample> {
+public class BandwidthUsageHistory implements 
Iterable<BandwidthUsageHistory.BandwidthUsageSample> {

        public class BandwidthUsageSample {
                private float value;
                private long time;

-               public BandwidthUsageSample(float newValue) {
+               public BandwidthUsageSample(float newValue, long newTime) {
                        value = newValue;
-                       time = System.currentTimeMillis();
+                       time = newTime;
                }

                public float getValue() {
                        return (value);
                }

-               public float setValue(float newValue) {
-                       time = System.currentTimeMillis();
+               public float setValue(float newValue, long newTime) {
+                       time = newTime;
                        return (value = newValue);
                }

@@ -46,48 +42,44 @@
                slot = 0;
        }

-       public BandwidthUsageHistory(BandwidthUsageSample[] newData) {
+       public BandwidthUsageHistory(BandwidthUsageSample[] newData, boolean 
bOldestIsNotIndex0) {
                if (newData == null)
                        throw new IllegalArgumentException("newData == null");

                data = newData;
                slot = 0;
-               long oldestTime = Long.MAX_VALUE;
-
-               /*
-                * Find the oldest slot and set slot to its index so that new 
values
-                * will be put into the right slots.
-                */
-               for (int idx = 0; idx < data.length; ++idx) {
-                       if (data[idx] != null && data[idx].getTime() < 
oldestTime) {
-                               slot = idx;
-                       }
-               }
+               
+               /* TODO: Remove if it is not needed by any caller. */
+               if(bOldestIsNotIndex0)
+                       slot = getOldestSampleIndex();
+               else
+                       assert(getOldestSampleIndex() == slot);
        }

        public int getSampleCount() {
-               return data.length;
+               return(data.length);
        }

-       public void putValue(float value) {
+       public synchronized void putValue(float value, long time) {
                slot = (slot + 1) % data.length;

                if (data[slot] == null)
-                       data[slot] = new BandwidthUsageSample(value);
+                       data[slot] = new BandwidthUsageSample(value, time);
                else
-                       data[slot].setValue(value);
+                       data[slot].setValue(value, time);
        }

-       public BandwidthUsageSample getSample(int idx) {
-               /*
-                * It should not be necessary for clients of this class to use 
values of
-                * idx greater than data.length.
-                */
+       /**
+        * Returns the <code>BandwidthUsageSample</code> with index 
<code>idx</code> from this object. Do not modify it, the original object
+        * is returned instead of a copy to prevent creation of large amounts 
of BandwidthUsageSample-objects.
+        */
+       public synchronized BandwidthUsageSample getSample(int idx) {
+               /* It should not be necessary for clients of this class to use 
values of idx greater than data.length, it will work however. */
                assert (idx >= 0 && idx < data.length);
-               return (data[(slot + idx) % data.length]);
+               return(data[(slot + idx) % data.length]);
        }

-       public float getAverage() {
+       public synchronized float getAverage() {
                float sum = 0.0f;
                int count = 0;
                for (int idx = 0; idx < data.length; ++idx) {
@@ -96,70 +88,77 @@
                                ++count;
                        }
                }
-               return (count != 0 ? (sum / count) : 0.0f);
+               return(count != 0 ? (sum / count) : 0.0f);
        }

        /**
-        * Calculates a new <code>BandwidthUsageHistory</code> with a smaller 
amount
-        * of samples. Each sample in the new <code>BandwidthUsageHistory</code>
-        * will be calculated as an average value over
-        * <code>this.getSampleCount() / numberOfSamples</code> samples. If
-        * <code>numberOfSamples</code> does not divide
-        * <code>this.getSampleCount()</code> then the oldest remaining samples 
from
-        * this object will not be included in the calculation.
+        * Calculates a new <code>BandwidthUsageHistory</code> with a smaller 
amount of samples. Each sample in the new
+        * <code>BandwidthUsageHistory</code> will be calculated as an average 
value over <code>this.getSampleCount() / numberOfSamples</code>
+        * samples. If <code>numberOfSamples</code> does not divide 
<code>this.getSampleCount()</code> then the oldest remaining samples from this
+        * object will not be included in the calculation.
         * 
         * @param numberOfSamples
         *            The number of samples which the new
         *            <code>BandwidthUsageHistory</code> should have.
         * @return The new <code>BandwidthUsageHistory</code>.
         */
-       public BandwidthUsageHistory getHistoryWithReducedSampleAmount(
-                       int numberOfSamples) {
+       public synchronized BandwidthUsageHistory 
getHistoryWithReducedSampleAmount(int numberOfSamples) {
                if (numberOfSamples > data.length)
-                       throw new IllegalArgumentException(
-                                       "numberOfSamples > this.data.length");
+                       throw new IllegalArgumentException("numberOfSamples > 
this.data.length");

                BandwidthUsageSample[] newData = new 
BandwidthUsageSample[numberOfSamples];
-
-               float value;
-               long startTime;
-               long endTime;
                int samplesPerValue = data.length / numberOfSamples;
+               
+               float value = 0.0f;
+               long startTime = -1; 
                int cnt = 0;
+               int newIdx = 0;

-               for (int idx = data.length % numberOfSamples; idx < data.length
-                               && data[idx] != null; idx++) {
-                       // time for a coffee, i'll finish that later :)
+               /* Start at data.length % numberOfSamples to drop the oldest 
remaining samples, see JavaDoc of this function */ 
+               for (int idx = data.length % numberOfSamples; idx < data.length 
&& data[idx] != null; ++idx) {
+                       BandwidthUsageSample s = getSample(idx);
+                       value += s.getValue();
+                       if(startTime < 0)
+                               startTime = s.getTime();
+               
+                       if(++cnt == samplesPerValue) {
+                               long endTime = s.getTime();
+                               assert(newIdx < newData.length); /* If this 
loop is constructed correctly we do not have to check newIdx. */ 
+                               newData[newIdx++] = new 
BandwidthUsageSample(value/samplesPerValue, startTime + (endTime-startTime) / 
2);
+                               cnt = 0;
+                               startTime = -1;
+                       }
                }

-               return new BandwidthUsageHistory(newData);
+               return(new BandwidthUsageHistory(newData, false));
        }

+       /**
+        * You HAVE TO use <code>synchronized(){}</code> on the 
BandwidthUsageHistory object when you use iterator()!
+        */
        public Iterator<BandwidthUsageSample> iterator() {
                return new Iterator<BandwidthUsageSample>() {
                        int idx = 0;

                        public boolean hasNext() {
-                               return (idx != data.length);
+                               return(idx != data.length);
                        }

+                       /**
+                        * Returns the next BandwidthUsageSample from this 
object. Do not modify it, the original object is returned instead of a copy to
+                        * prevent creation of large amounts of 
BandwidthUsageSample-objects.
+                        */
                        public BandwidthUsageSample next() {
                                if (!hasNext())
                                        throw new NoSuchElementException();

-                               /*
-                                * We do not clone() it to prevent generation 
of insane amounts
-                                * of objects, the client classes are trusted 
not to damage the
-                                * referenced objects they receive
-                                */
-                               BandwidthUsageSample result = data[(slot + idx) 
% data.length];
+                               BandwidthUsageSample result = getSample(idx);
                                ++idx;
-                               return result;
+                               return(result);
                        }

                        /**
-                        * This cannot be used: The BandwidthUsageHistory 
contains a fixed
-                        * amount of elements.
+                        * This cannot be used: The BandwidthUsageHistory 
contains a fixed amount of elements.
                         */
                        public void remove() {
                                throw new UnsupportedOperationException();
@@ -167,4 +166,21 @@

                };
        }
+       
+       /**
+        * Uses O(data.length) time! Should be avoided!
+        * @return The index of the oldest sample in the data.
+        */
+       protected int getOldestSampleIndex() {
+               int oldest = 0;
+               long oldestTime = Long.MAX_VALUE;
+
+               for (int idx = 0; idx < data.length; ++idx) {
+                       if (data[idx] != null && data[idx].getTime() < 
oldestTime) {
+                               oldest = idx;
+                       }
+               }
+               
+               return(oldest);
+       }
 }


Reply via email to