Author: robert
Date: 2007-12-26 20:51:38 +0000 (Wed, 26 Dec 2007)
New Revision: 16817

Added:
   trunk/freenet/src/freenet/support/math/DecayingKeyspaceAverage.java
Modified:
   trunk/freenet/src/freenet/node/Location.java
   trunk/freenet/src/freenet/node/NodeStats.java
Log:
implement keyspace-aware averager


Modified: trunk/freenet/src/freenet/node/Location.java
===================================================================
--- trunk/freenet/src/freenet/node/Location.java        2007-12-26 20:48:13 UTC 
(rev 16816)
+++ trunk/freenet/src/freenet/node/Location.java        2007-12-26 20:51:38 UTC 
(rev 16817)
@@ -70,6 +70,20 @@
                }
        }

+       /**
+        * Given an arbitrary double (not bound to [0.0, 1.0]) return the 
normalized double [0.0, 1.0] which would result in simple
+        * wrapping/overflowing. e.g. normalize(1.0+0.5)==0.5, 
normalize(0.5-1.0)==0.5, normalize({0.0,1.0})=={0.0,1.0}
+        * @bug: if given double has wrapped too many times, the return value 
may be not be precise.
+        */
+       public static double normalize(double rough) {
+               int intPart=(int)rough;
+               double maybeNegative=rough-intPart;
+               //note: maybeNegative is bound between (-1.0, 1.0)
+               if (maybeNegative < 0)
+                       return 1.0+maybeNegative;
+               return maybeNegative;
+       }
+       
        public static boolean equals(double newLoc, double currentLocation) {
                return Math.abs(newLoc - currentLocation) < Double.MIN_VALUE * 
2;
        }

Modified: trunk/freenet/src/freenet/node/NodeStats.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeStats.java       2007-12-26 20:48:13 UTC 
(rev 16816)
+++ trunk/freenet/src/freenet/node/NodeStats.java       2007-12-26 20:51:38 UTC 
(rev 16817)
@@ -23,6 +23,7 @@
 import freenet.support.api.IntCallback;
 import freenet.support.api.LongCallback;
 import freenet.support.math.BootstrappingDecayingRunningAverage;
+import freenet.support.math.DecayingKeyspaceAverage;
 import freenet.support.math.RunningAverage;
 import freenet.support.math.TimeDecayingRunningAverage;
 import freenet.support.math.TrivialRunningAverage;
@@ -189,11 +190,11 @@
                this.backedOffPercent = new TimeDecayingRunningAverage(0.0, 
180000, 0.0, 1.0, node);
                double nodeLoc=node.lm.getLocation();
                // FIXME PLEASE; (int) casts; (maxCacheKeys>MAXINT?) This value 
will probably end up being a small constant anyway (200?).
-               this.avgCacheLocation   = new 
BootstrappingDecayingRunningAverage(nodeLoc, 0.0, 1.0, (int)node.maxCacheKeys, 
null);
-               this.avgStoreLocation   = new 
BootstrappingDecayingRunningAverage(nodeLoc, 0.0, 1.0, (int)node.maxStoreKeys, 
null);
-               this.avgCacheSuccess    = new 
BootstrappingDecayingRunningAverage(nodeLoc, 0.0, 1.0, 10000, null);
-               this.avgStoreSuccess    = new 
BootstrappingDecayingRunningAverage(nodeLoc, 0.0, 1.0, 10000, null);
-               this.avgRequestLocation = new 
BootstrappingDecayingRunningAverage(nodeLoc, 0.0, 1.0, 10000, null);
+               this.avgCacheLocation   = new DecayingKeyspaceAverage(nodeLoc, 
(int)node.maxCacheKeys, null);
+               this.avgStoreLocation   = new DecayingKeyspaceAverage(nodeLoc, 
(int)node.maxStoreKeys, null);
+               this.avgCacheSuccess    = new DecayingKeyspaceAverage(nodeLoc, 
10000, null);
+               this.avgStoreSuccess    = new DecayingKeyspaceAverage(nodeLoc, 
10000, null);
+               this.avgRequestLocation = new DecayingKeyspaceAverage(nodeLoc, 
10000, null);
                preemptiveRejectReasons = new StringCounter();
                localPreemptiveRejectReasons = new StringCounter();
                pInstantRejectIncoming = new TimeDecayingRunningAverage(0, 
60000, 0.0, 1.0, node);

Added: trunk/freenet/src/freenet/support/math/DecayingKeyspaceAverage.java
===================================================================
--- trunk/freenet/src/freenet/support/math/DecayingKeyspaceAverage.java         
                (rev 0)
+++ trunk/freenet/src/freenet/support/math/DecayingKeyspaceAverage.java 
2007-12-26 20:51:38 UTC (rev 16817)
@@ -0,0 +1,139 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.support.math;
+
+import freenet.node.Location;
+
+import freenet.support.Logger;
+import freenet.support.SimpleFieldSet;
+
+/**
+ * @author robert
+ *
+ * A filter on BootstrappingDecayingRunningAverage which makes it aware of the 
circular keyspace.
+ */
+public class DecayingKeyspaceAverage implements RunningAverage {
+       /**
+        'avg' is the non-normalized average location.
+        */
+       BootstrappingDecayingRunningAverage avg;
+       
+       //If the keyspace averager wraps more than this number of times, an 
exception will be thrown.
+       public final static int WRAP_WARNING=1000;
+       
+       public DecayingKeyspaceAverage(double defaultValue, int maxReports, 
SimpleFieldSet fs) {
+               avg=new BootstrappingDecayingRunningAverage(defaultValue, 
-WRAP_WARNING, WRAP_WARNING, maxReports, fs);
+       }
+       
+       public DecayingKeyspaceAverage(BootstrappingDecayingRunningAverage a) {
+               //check the max/min values? ignore them?
+               avg=(BootstrappingDecayingRunningAverage)a.clone();
+       }
+       
+       public synchronized Object clone() {
+               return new DecayingKeyspaceAverage(avg);
+       }
+    
+       public synchronized double currentValue() {
+               return Location.normalize(avg.currentValue());
+       }
+       
+       public synchronized void report(double d) {
+               if ((d < 0.0) || (d > 1.0)) {
+                       //Just because we use non-normalized locations doesn't 
mean we can accept them.
+                       throw new IllegalArgumentException("Not a valid 
normalized key: "+d);
+        }
+               double superValue=avg.currentValue();
+               double thisValue=Location.normalize(superValue);
+               double diff=Location.change(thisValue, d);
+               double toAverage=(superValue+diff);
+               /*
+                To gracefully wrap around the 1.0/0.0 threshold we average 
over (or under) it, and simply normalize the result when reporting a 
currentValue
+                ---example---
+                d=0.2;          //being reported
+                superValue=1.9; //already wrapped once, but at 0.9
+                thisValue=0.9;  //the normalized value of where we are in the 
keyspace
+                diff = +0.3;    //the diff from the normalized values; 
Location.change(0.9, 0.2);
+                avg.report(2.2);//to successfully move the average towards the 
closest route to the given value.
+                */
+               //System.err.println("debug: "+superValue+", "+thisValue+", 
"+diff+", "+(superValue+diff)+", "+Location.normalize(superValue+diff));
+               if (toAverage>WRAP_WARNING || toAverage<-WRAP_WARNING)
+                       Logger.error(this, "DecayingKeyspaceAverage is wrapped 
up too many times");
+               avg.report(toAverage);
+       }
+       
+    public synchronized double valueIfReported(double d) {
+               if ((d < 0.0) || (d > 1.0)) {
+                       throw new IllegalArgumentException("Not a valid 
normalized key: "+d);
+        }              
+               double superValue=avg.currentValue();
+               double thisValue=Location.normalize(superValue);
+               double diff=Location.change(thisValue, d);
+               return avg.valueIfReported(superValue+diff);
+       }
+       
+    public synchronized long countReports() {
+               return avg.countReports();
+       }
+       
+       public void report(long d) {
+               throw new IllegalArgumentException("KeyspaceAverage does not 
like longs");
+       }
+       
+       ///@todo: make this a junit test
+       public static void main(String[] args) {
+               DecayingKeyspaceAverage a=new DecayingKeyspaceAverage(0.9, 10, 
null);
+               a.report(0.9);
+               for (int i=10; i!=0; i--) {
+                       a.report(0.2);
+                       System.out.println("<-0.2-- current="+a.currentValue());
+               }
+               for (int i=10; i!=0; i--) {
+                       a.report(0.8);
+                       System.out.println("--0.8-> current="+a.currentValue());
+               }
+               System.out.println("--- positive wrap test ---");
+               for (int wrap=3; wrap!=0; wrap--) {
+                       System.out.println("wrap test #"+wrap);
+                       for (int i=10; i!=0; i--) {
+                               a.report(0.25);
+                               System.out.println("<-0.25- 
current="+a.currentValue());
+                       }
+                       for (int i=10; i!=0; i--) {
+                               a.report(0.5);
+                               System.out.println("--0.5-> 
current="+a.currentValue());
+                       }
+                       for (int i=10; i!=0; i--) {
+                               a.report(0.75);
+                               System.out.println("-0.75-> 
current="+a.currentValue());
+                       }
+                       for (int i=10; i!=0; i--) {
+                               a.report(1.0);
+                               System.out.println("<-1.0-- 
current="+a.currentValue());
+                       }
+               }
+               System.out.println("--- negative wrap test ---");
+               a=new DecayingKeyspaceAverage(0.2, 10, null);
+               a.report(0.2);
+               for (int wrap=3; wrap!=0; wrap--) {
+                       System.out.println("negwrap test #"+wrap);
+                       for (int i=10; i!=0; i--) {
+                               a.report(0.75);
+                               System.out.println("-0.75-> 
current="+a.currentValue());
+                       }
+                       for (int i=10; i!=0; i--) {
+                               a.report(0.5);
+                               System.out.println("<-0.5-- 
current="+a.currentValue());
+                       }
+                       for (int i=10; i!=0; i--) {
+                               a.report(0.25);
+                               System.out.println("<-0.25- 
current="+a.currentValue());
+                       }
+                       for (int i=10; i!=0; i--) {
+                               a.report(1.0);
+                               System.out.println("--1.0-> 
current="+a.currentValue());
+                       }
+               }
+       }
+}
\ No newline at end of file


Reply via email to