Update of /cvsroot/freenet/freenet/src/freenet/node/rt
In directory sc8-pr-cvs1:/tmp/cvs-serv9927/src/freenet/node/rt

Modified Files:
        ResponseTimeEstimator.java FFTTimeEstimator.java 
Added Files:
        RoutingPointStore.java 
Log Message:
Moved RoutingPointStore into a separate class in order to support better access 
control (using private/public methods etc).
Fix m0davis graph NPE.

--- NEW FILE: RoutingPointStore.java ---
package freenet.node.rt;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import freenet.support.sort.QuickSorter;
import freenet.support.sort.Sortable;
import freenet.Core;
import freenet.support.Logger;
import freenet.Key;


class RoutingPointStore {
        RoutingPoint points[];
        final RoutingPointStore.RoutingPointKeySorter ms = new RoutingPointKeySorter();
        boolean logDEBUG = true;
        final BigInteger keyspace;
        static final int MAX_ACCURACY = 32;
        
        //Represents a point in a routing graph
        //Is the fundamental storage item of the RoutingStore
        class RoutingPoint {
                //Underlying values write accessible only to this class
                //If anyone wants to modify RoutingPoints they need to use
                //a RoutingPointEditor instance
                private BigInteger key;
                private int time;
                private double sensitivity;
                RoutingPoint() {
                        key = null;
                        time = 0;
                        sensitivity = 0;
                }
                RoutingPoint(BigInteger key, int time, double sensitivity) {
                        this.key = key;
                        this.time = time;
                        this.sensitivity = sensitivity;
                }
                
                //Expose underlying values for reading only to others
                public BigInteger getKey() {
                        return key;
                }

                public double getSensitivity() {
                        return sensitivity;
                }

                public int getTime() {
                        return time;
                }

        }
        class RoutingPointEditor {
                private RoutingPoint p;
                private BigInteger key;
                private int time;
                private double sensitivity;
                private boolean keyDirty,timeDirty,sensitivityDirty;

                RoutingPointEditor(RoutingPoint p) {
                        this.p = p;
                        keyDirty = timeDirty = sensitivityDirty = false;
                }
                void commit(){
                        synchronized(RoutingPointStore.this){
                                p.key = key;
                                p.time = time;
                                p.sensitivity = sensitivity;
                        }
                        keyDirty = timeDirty = sensitivityDirty = false;
                }
                public BigInteger getKey() {
                        if(keyDirty)
                                return key;
                        else
                                return p.key;
                }
                public void setKey(BigInteger key) {
                        this.key = key;
                        keyDirty = true;
                }

                public double getSensitivity() {
                        if(sensitivityDirty)
                                return sensitivity;
                        else
                                return p.sensitivity;
                }

                public void setSensitivity(double sensitivity) {
                        this.sensitivity = sensitivity;
                        sensitivityDirty = true;
                }

                public int getTime() {
                        if(timeDirty)
                                return time;
                        else
                                return p.time;
                }

                public void setTime(int time) {
                        this.time = time;
                        timeDirty = true;
                }
        }
        
        //A pair of two neighbouring RoutingPoints, including information on wheter or 
not
        //there is a keyspace wrap between them (right-key actually a larger value 
than left-key)
        class NeighbourRoutingPointPair {
                RoutingPointStore.RoutingPoint left, right; //The key before and the 
key after the supplied key
                boolean includesKeyspaceWrap; //Wheter or not a keyspace wrap is 
actually between the two RoutingPoints
                int nPos; //TODO:Get rid of this one. The position of the key that 
before and after is just that.
        }
        
        //Sorts the store in order of the RoutingPoint keys.
        private final class RoutingPointKeySorter implements Sortable {
                public final int compare(int index1, int index2) {
                        return points[index1].key.compareTo(points[index2].key);
                }

                public final void swap(int index1, int index2) {
                        RoutingPoint p = points[index1];
                        points[index1] = points[index2];
                        points[index2] = p;
                }

                public final int size() {
                        return length();
                }
        }

        //Create fresh routing store with 'accuracy' number of default-valued 
RoutingPoints
        public RoutingPointStore(int accuracy,int initTime,BigInteger keyspace) {
                this.keyspace = keyspace;
                points = new RoutingPoint[accuracy];
                for (int x = 0; x < points.length; x++) {
                        points[x] = new RoutingPoint();
                }
                setAllTimes(initTime);
                logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
        }

        //Create a store by reading a serialization
        public RoutingPointStore(DataInputStream i,BigInteger keyspace) throws 
IOException {
                this.keyspace = keyspace;
                logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
                int accuracy = i.readInt();
                if (accuracy < 0)
                        throw new IOException("failed read");
                if (accuracy == 0 || accuracy > MAX_ACCURACY) // seems reasonable 
bounds
                        throw new IOException("Invalid accuracy word " + accuracy);
                points = new RoutingPoint[accuracy];
                
                
                BigInteger prev = BigInteger.ZERO;

                for (int x = 0; x < points.length; x++) {
                        int time = i.readInt();
                        //time[x] = i.readInt();
                        if (time < 0)
                                throw new IOException("negative value");
                        byte[] b = new byte[Key.KEYBYTES];
                        i.readFully(b);
                        BigInteger key = new BigInteger(1, b);
                        if (key.signum() == -1)
                                throw new IOException("negative key");
                        if (key.compareTo(keyspace) == 1)
                                throw new IOException("exceeded keyspace");
                        if (key.compareTo(prev) == -1)
                                throw new IOException("smaller than prev");
                        prev = key;
                        double sensitivity = i.readDouble();
                        points[x] = new RoutingPoint(key,time,sensitivity);
                }
        }
        //TODO: Documentation
        public RoutingPointStore(Key k, int high, int low, int accuracy,BigInteger 
keyspace) {
                this(accuracy,-1,keyspace);
//              We will overwrite the initTime:s in as second so they doesn't really 
matter.
                //Make sure that we detect any assignment problems but setting 
initTime to -1 
                if (high < 0 || low < 0)
                        throw new IllegalArgumentException("negative high " + high + " 
or low " + low);
                // Center on k
                // b = keyspace / accuracy
                // c = k % c
                // Then set keys as in monadic constructor, except adding k
                BigInteger a = keyspace.subtract(BigInteger.ONE);
                BigInteger b = a.divide(BigInteger.valueOf(accuracy));
                BigInteger ik = k.toBigInteger(); 
                BigInteger[] dr = ik.divideAndRemainder(b);
                BigInteger c = dr[1]; // remainder. positive!
                if (c.signum() < 0)
                        throw new IllegalStateException("argh");
                int kOffset = dr[0].intValue();
                for (int i = 0; i < accuracy; i++) {
                        points[i].key = c;
                        c.add(b);
                }
                // Now the times
                int val = high;
                int valStep = (high - low) / accuracy;
                for (int i = 0; i < accuracy; i++) {
                        int offset = (kOffset + i) % accuracy;
                        points[offset].time = val;
                        if (i <= accuracy / 2)
                                val -= valStep;
                        else
                                val += valStep;
                }
                //TODO: What about the sensitivities?
        }

        //Returns the offset of the biggest key that's still less than n.
        final synchronized int search(BigInteger n) {
                int mid, low = 0, high = points.length - 1;

                for (;;) {
                        mid = (high + low) >> 1;
                        int i = points[mid].key.compareTo(n);
                        if (i <= 0 && points[mid+1].key.compareTo(n) > 0)
                                return mid;
                        if (i > 0)
                                high = mid;
                        else
                                low = mid + 1;
                        if (low == high)
                                return low;
                }
        }

        //Sets all times to the supplied value
        private synchronized void setAllTimes(int newtime) {
                for (int i = 0; i < points.length; i++) {
                        points[i].time = newtime;
                }
        }
        
        //Returns a RoutingPointEditor for the Point at the position 'index' in the 
store
        //The RoutingPointEditor can be used to modify the routingPoint
        synchronized RoutingPointEditor checkout(int index) {
                return new RoutingPointEditor(points[index]);
        }
        
        //Returns the RoutingPoint at the position 'index' in the store
        //The RoutingPointreturned might *not* be modified
        synchronized RoutingPoint get(int index) {
                return points[index];
        }
        

        //Finds the position of the first key in the store, before the position 
'startAt', that is smaller than n
        //Returns -1 if no such key is present in the store
        protected synchronized int findFirstSmaller_reverse(BigInteger n, int startAt) 
{
                while (points[startAt].key.compareTo(n) == 1) {
                        startAt--;
                        if (startAt < 0)
                                return -1;
                }
                return startAt;
        }
        //Finds the position of the first key in the store, after the position 
'startAt', that is larger than n
        //Returns -1 if no such key is present in the store
        protected synchronized int findFirstLarger(BigInteger n, int startAt) {
                while (points[startAt].key.compareTo(n) == -1) {
                        startAt++;
                        if (startAt >= points.length)
                                return -1;
                }
                return startAt;
        }

        int getDataLength() {
                //TODO: What about the times and sensitivities. Shouldn't they be 
included in the size?
                return 4 + points.length * (4 + Key.KEYBYTES);
        }
        
        //Returns the number of items in the store
        int length() {
                return points.length;
        }
        
        public synchronized void dumpLog() {
                if (Core.logger.shouldLog(Logger.MINOR, this)) {
                        StringBuffer sb = new StringBuffer();
                        for (int x = 0; x < points.length; x++) {
                                sb.append(points[x].key.toString(16));
                                sb.append(": ");
                                int t = points[x].time;
                                sb.append(Integer.toString(t));
                                if (t < 0)
                                        Core.logger.log(this, "time[" + x + "]=" + t + 
" - NEGATIVE (" + this +")", Logger.ERROR);
                                sb.append("\n");
                        }
                        Core.logger.log(this, "Dump of " + this +": \n" + 
sb.toString(), Logger.MINOR);
                } else {
                        //Do only the sanity check if we wont log the contents of the 
estimator
                        for (int x = 0; x < points.length; x++) {
                                int t = points[x].time;
                                if (t < 0)
                                        Core.logger.log(this, "time[" + x + "]=" + t + 
" - NEGATIVE (" + this +")", Logger.ERROR);
                        }
                }
        }
        synchronized void dumpHtml(PrintWriter pw) {
                for (int x = 0; x < points.length; x++) {
                        pw.println("<tr><td>" + x + "</td><td>" + 
points[x].key.toString(16) + "</td><td>" + points[x].time + "</td><td>" + 
points[x].sensitivity + "</td></tr>");
                        if (points[x].time < 0)
                                Core.logger.log(this, "time[" + x + "]=" + 
points[x].time + " - NEGATIVE (" + this +")", Logger.ERROR);
                }
        }
        //Returns the value (time) of the highest-valued RoutingPoint
        public synchronized long highestRaw() {
                int highest = 0;
                for (int x = 0; x < points.length; x++) {
                        highest = Math.max(highest,points[x].time);
                }
                return highest;
        }
        //Returns the value (time) of the lowest-valued RoutingPoint
        public synchronized long lowestRaw() {
                int lowest = Integer.MAX_VALUE;
                for (int x = 0; x < points.length; x++) {
                        lowest = Math.min(lowest,points[x].time);
                }
                return lowest;
        }
        public synchronized void print() {
                for (int i = 0; i < points.length; i++)
                        System.out.println(i + ":\t" + points[i].key + "\t" + 
points[i].time);
        }
        //Sorts the RoutingStore in order of its RoutingPoint keys
        protected synchronized void sortByKey() {
                if (logDEBUG)
                        Core.logger.log(this, "Reordering keys", Logger.DEBUG);
                dumpLog();
                // We cannot simply find the lowest value and then shift,
                // Becuase we are not using anything like strict gravity
                // We move the first key 1/2 the distance closer, the second 1/4 its 
distance
                // closer, the third 1/8 its distance closer etc
                // They get reordered!
                QuickSorter.quickSort(ms);
                dumpLog();
        }

        //Serializes the store to the supplied DataOutputStream
        public synchronized void writeTo(DataOutputStream o) throws IOException {
                logDEBUG = Core.logger.shouldLog(Logger.DEBUG, this);
                if (logDEBUG)
                        Core.logger.log(this,"Serializing store to disk, accuracy " + 
points.length, Logger.DEBUG);
                o.writeInt(points.length);
                for (int i = 0; i < points.length; i++) {
                        o.writeInt(points[i].time);
                        byte[] b = points[i].key.toByteArray();
                        if (b.length > Key.KEYBYTES + 1)
                                throw new IllegalStateException("Key too long in 
serializing: " + b.length);
                        if (b.length < Key.KEYBYTES) {
                                int skip = Key.KEYBYTES - b.length;
                                for (int x = 0; x < skip; x++)
                                        o.writeByte(0);
                                o.write(b);
                        } else
                                o.write(b, b.length - Key.KEYBYTES, Key.KEYBYTES);
                        // in case of zero padding
                        o.writeDouble(points[i].sensitivity);
                }
        }

        //Returns the RoutingPoint which has the highest key
        private RoutingPoint lastPoint() {
                return get(points.length - 1);
        }
        //Returns the RoutingPoint which has the lowest key
        private RoutingPoint firstPoint() {
                return get(0);
        }
        //distributes the keys evenly throughout all of the keyspace
        synchronized void distributeKeysEvenly() {
                BigInteger a = keyspace.subtract(BigInteger.ONE);
                BigInteger b = a.divide(BigInteger.valueOf(points.length));
                for (int i = points.length; --i >= 0; a = a.subtract(b))
                        points[i].key = a;
        }

        //Locates the RoutingPoints who are keywise located right before and right 
after the supplied BigInteger
        //Handles keyspace wrap situations. The returned class contains information 
wheter or not a wrap occurred
        //The RoutingPoints returned might *not* be edited!
        synchronized NeighbourRoutingPointPair findKeyBeforeAndAfter(BigInteger n) {
                NeighbourRoutingPointPair retval = new NeighbourRoutingPointPair();
                int pos = search(n);

                retval.nPos = pos;
                //Is it off the keyspace, either to the left or to the right...
                if ((pos == 0 && n.compareTo(firstPoint().key) < 0) || (pos == 
length() - 1)) {
                        // Off the end/beginning
                        // Doesn't matter which
                        retval.includesKeyspaceWrap = true;
                        pos = length() - 1;
                        //Yes, beforeKey should be negative
                        retval.left = new 
RoutingPoint(lastPoint().key.subtract(keyspace), points[pos].time, 
points[pos].sensitivity);
                        retval.right = get(0);
                } else {//else in the middle
                        retval.includesKeyspaceWrap = false;
                        retval.left = get(pos);
                        retval.right = get(pos+1);
                }
                return retval;
        }
}/*
 * Created on Nov 2, 2003
 *
*/

Index: ResponseTimeEstimator.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/node/rt/ResponseTimeEstimator.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -w -r1.28 -r1.29
--- ResponseTimeEstimator.java  1 Nov 2003 22:54:02 -0000       1.28
+++ ResponseTimeEstimator.java  3 Nov 2003 08:04:53 -0000       1.29
@@ -3,7 +3,6 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.text.NumberFormat;
@@ -17,8 +16,7 @@
 import freenet.support.graph.BitmapEncoder;
 import freenet.support.graph.Color;
 import freenet.support.graph.DibEncoder;
-import freenet.support.sort.QuickSorter;
-import freenet.support.sort.Sortable;
+
 
 // class Key {
 //     byte[] b;
@@ -44,15 +42,13 @@
     protected RecentReports recent;
     protected RoutingPointStore store;
     
-    static final int KEYBYTES = 23,
-                     TIMEBYTES = 4,
-                     BYTES = KEYBYTES + TIMEBYTES;
+    static final int TIMEBYTES = 4,
+                     BYTES = Key.KEYBYTES + TIMEBYTES;
     
     static final int DEFAULT_ACCURACY = 16;
-    static final int MAX_ACCURACY = 32;
-    static final BigInteger keyspace = BigInteger.ONE.shiftLeft(KEYBYTES << 3);
+    static final BigInteger keyspace = BigInteger.ONE.shiftLeft(Key.KEYBYTES << 3);
     static final BigInteger halfkeyspace = 
-       BigInteger.ONE.shiftLeft((KEYBYTES << 3) - 1);
+       BigInteger.ONE.shiftLeft((Key.KEYBYTES << 3) - 1);
     boolean logDEBUG = true;
     
     public int getDataLength() {
@@ -62,7 +58,7 @@
     public ResponseTimeEstimator(DataInputStream i) throws IOException {
        int version = i.readInt();
        if(version != 1) throw new IOException("unrecognized version "+i);
-       store = new RoutingPointStore(i);
+       store = new RoutingPointStore(i,keyspace);
        try {
                recent = new RecentReports(i);
        } catch (IOException e) {
@@ -108,41 +104,21 @@
     }
     
     public ResponseTimeEstimator(int initTime, int accuracy) {
-       this(accuracy);
+               store = new RoutingPointStore(accuracy,initTime,keyspace);
        if(initTime < 0) throw new IllegalArgumentException("negative initTime");
-       store.setAllTimes(initTime);
+               recent = new RecentReports();
     }
     
        public ResponseTimeEstimator(Key k, int high, int low, int accuracy) {
-               store = new RoutingPointStore(k,high,low,accuracy);
+               store = new RoutingPointStore(k,high,low,accuracy,keyspace);
                recent = new RecentReports();
        }
     
     public ResponseTimeEstimator(int accuracy) {
-               store = new RoutingPointStore(accuracy);
-
+               this(0,accuracy);
                // Let's evenly distribute the keys across the whole
                // keyspace and leave the time values at zero.
                store.distributeKeysEvenly();
-               store.setAllTimes(0);
-               recent = new RecentReports();
-       }
-
-       
-    // Interpret key as value between 0 and 2^183.
-       final BigInteger convert(Key k) {
-               byte[] b = k.getVal();
-               if (b.length < KEYBYTES) {
-                       byte[] ob = new byte[KEYBYTES];
-                       System.arraycopy(b, 0, ob, 0, b.length);
-                       b = ob;
-               }
-               if (b.length > KEYBYTES) {
-                       Core.logger.log(this, "Very long key detected!: " + k, new 
Exception("debug"), Logger.NORMAL);
-                       byte[] ob = new byte[KEYBYTES];
-                       System.arraycopy(b, 0, ob, 0, KEYBYTES);
-               }
-               return new BigInteger(1, b);
        }
     
 
@@ -175,14 +151,14 @@
                if (lowerBoundPos > upperBoundPos)
                        return initialSteps;
                for (int i = lowerBoundPos; i <= upperBoundPos; i++) {
-                       RoutingPointStore.RoutingPoint k = store.get(i);
-                       if (k.time < 0)
-                               Core.logger.log(this, "time[" + i + "] = " + k.time + 
" - NEGATIVE TIME!", Logger.ERROR);
+                       RoutingPointStore.RoutingPointEditor k = store.checkout(i);
+                       if (k.getTime() < 0)
+                               Core.logger.log(this, "time[" + i + "] = " + 
k.getTime() + " - NEGATIVE TIME!", Logger.ERROR);
                        if (logDEBUG)
-                               Core.logger.log(this, "Trying key[" + i + "]: " + 
k.key.toString(16) + "," + k.time, Logger.DEBUG);
-                       k.sensitivity = Math.min(k.sensitivity,SENSITIVITY_MAX);
+                               Core.logger.log(this, "Trying key[" + i + "]: " + 
k.getKey().toString(16) + "," + k.getTime(), Logger.DEBUG);
+                       k.setSensitivity(Math.min(k.getSensitivity(),SENSITIVITY_MAX));
                        //double sens = sensitivity[i];
-                       BigInteger diff = handleKeyspaceWrap(k.key.subtract(center));
+                       BigInteger diff = 
handleKeyspaceWrap(k.getKey().subtract(center));
                        // Result = old position + ((old position * sensitivity) / 
(sensitivity + 1)
                        // >> shiftAmount
 
@@ -195,20 +171,20 @@
                         */
                        // Multiply by 75% to prevent points from collapsing on each 
other
                        BigDecimal fracDiff = new BigDecimal(diff);
-                       BigDecimal fracSens = new BigDecimal(k.sensitivity);
+                       BigDecimal fracSens = new BigDecimal(k.getSensitivity());
                        BigDecimal fracOrig = new BigDecimal(center);
                        BigDecimal resultDiff = fracDiff.divide(fracSens.add(DEC_ONE), 
BigDecimal.ROUND_DOWN);
                        diff = resultDiff.toBigInteger().shiftRight(shiftAmount);
                        diff = diff.multiply(THREE).divide(FOUR);
-                       k.key = handleKeyspaceWrap(k.key.subtract(diff));
+                       k.setKey(handleKeyspaceWrap(k.getKey().subtract(diff)));
 
-                       int timediff = usec - k.time;
+                       int timediff = usec - k.getTime();
                        if (logDEBUG)
-                               Core.logger.log(this, "usec=" + usec + ", time[" + i + 
"]=" + k.time + ", timediff=" + timediff, Logger.DEBUG);
+                               Core.logger.log(this, "usec=" + usec + ", time[" + i + 
"]=" + k.getTime() + ", timediff=" + timediff, Logger.DEBUG);
                        double fracTimediff = (double) timediff;
                        if (logDEBUG)
                                Core.logger.log(this, "fracTimediff=" + fracTimediff, 
Logger.DEBUG);
-                       double resultTimediff = fracTimediff / (k.sensitivity + 1.0);
+                       double resultTimediff = fracTimediff / (k.getSensitivity() + 
1.0);
                        if (logDEBUG)
                                Core.logger.log(this, "resultTimediff=" + 
resultTimediff, Logger.DEBUG);
                        timediff = ((int) resultTimediff) >> shiftAmount;
@@ -216,14 +192,14 @@
                                Core.logger.log(this, "timediff now = " + timediff, 
Logger.DEBUG);
                        timediff = (int) ((((long) timediff) * 3) / 4);
                        if (logDEBUG)
-                               Core.logger.log(this, "time[" + i + "] = " + k.time + 
", timediff = " + timediff, Logger.DEBUG);
-                       k.time += timediff;
+                               Core.logger.log(this, "time[" + i + "] = " + 
k.getTime() + ", timediff = " + timediff, Logger.DEBUG);
+                       k.setTime(k.getTime()+ timediff);
                        if (logDEBUG)
-                               Core.logger.log(this, "key[" + i + "] now: " + 
k.key.toString(16) + "," + k.time, Logger.DEBUG);
-                       if (k.time < 0)
-                               Core.logger.log(this, "time[" + i + "] = " + k.time + 
" - NEGATIVE TIME!", Logger.ERROR);
-                       k.sensitivity += 1.0 / (1 << shiftAmount);
-                       store.set(i,k);
+                               Core.logger.log(this, "key[" + i + "] now: " + 
k.getKey().toString(16) + "," + k.getTime(), Logger.DEBUG);
+                       if (k.getTime() < 0)
+                               Core.logger.log(this, "time[" + i + "] = " + 
k.getTime() + " - NEGATIVE TIME!", Logger.ERROR);
+                       k.setSensitivity(k.getSensitivity()+ 1.0 / (1 << shiftAmount));
+                       k.commit();
                        shiftAmount++;
                }
                store.dumpLog();
@@ -274,40 +250,40 @@
        
        if(lowerBoundPos > upperBoundPos) return initialSteps;
        for(int i=upperBoundPos;i>=lowerBoundPos;i--) {
-               RoutingPointStore.RoutingPoint k = store.get(i);
+               RoutingPointStore.RoutingPointEditor k = store.checkout(i);
            if(logDEBUG)
                Core.logger.log(this, "Trying key["+i+"]: "+
-                               k.key.toString(16)+","+k.time, 
+                               k.getKey().toString(16)+","+k.getTime(), 
                                Logger.DEBUG);
-           if(k.time < 0)
-               Core.logger.log(this, "time["+i+"] = "+k.time+
+           if(k.getTime() < 0)
+               Core.logger.log(this, "time["+i+"] = "+k.getTime()+
                                " - NEGATIVE TIME!", Logger.ERROR);
-           k.sensitivity = Math.min(k.sensitivity,SENSITIVITY_MAX);
+           k.setSensitivity(Math.min(k.getSensitivity(),SENSITIVITY_MAX));
            //double sens = sensitivity[i];
-           BigInteger diff = handleKeyspaceWrap(center.subtract(k.key));
+           BigInteger diff = handleKeyspaceWrap(center.subtract(k.getKey()));
            BigDecimal fracDiff = new BigDecimal(diff);
-           BigDecimal fracSens = new BigDecimal(k.sensitivity);
+           BigDecimal fracSens = new BigDecimal(k.getSensitivity());
            BigDecimal fracOrig = new BigDecimal(center);
            BigDecimal resultDiff = fracDiff.divide(fracSens.add(DEC_ONE),
                                                    BigDecimal.ROUND_DOWN);
            diff = resultDiff.toBigInteger().shiftRight(shiftAmount);
            diff = diff.multiply(THREE).divide(FOUR);
-           k.key = handleKeyspaceWrap(k.key.add(diff.shiftRight(shiftAmount)));
-           int timediff = usec - k.time;
+           k.setKey(handleKeyspaceWrap(k.getKey().add(diff.shiftRight(shiftAmount))));
+           int timediff = usec - k.getTime();
            double fracTimediff = (double)timediff;
-           double resultTimediff = fracTimediff/(k.sensitivity+1.0);
+           double resultTimediff = fracTimediff/(k.getSensitivity()+1.0);
            timediff = ((int)resultTimediff) >> shiftAmount;
            timediff = (int)((((long)timediff)*3)/4);
-           k.time += timediff;
+           k.setTime( k.getTime()+ timediff);
            if(logDEBUG)
-               Core.logger.log(this, "key["+i+"] now: "+k.key.toString(16)+
-                               ","+k.time, Logger.DEBUG);
-           k.sensitivity += 1.0/(1<<shiftAmount);
+               Core.logger.log(this, "key["+i+"] now: "+k.getKey().toString(16)+
+                               ","+k.getTime(), Logger.DEBUG);
+           k.setSensitivity(k.getSensitivity() + 1.0/(1<<shiftAmount));
            shiftAmount++;
-           if(k.time < 0)
-               Core.logger.log(this, "time["+i+"] = "+k.time+
+           if(k.getTime() < 0)
+               Core.logger.log(this, "time["+i+"] = "+k.getTime()+
                                " - NEGATIVE TIME!", Logger.ERROR);
-           store.set(i,k);
+           k.commit();
        }
        store.dumpLog();
        return shiftAmount;
@@ -317,7 +293,7 @@
 
        public synchronized void report(Key k, int usec) {
        logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
-        BigInteger n = convert(k);
+        BigInteger n = k.toBigInteger();
        
        if(usec < 0) throw new IllegalArgumentException("negative usec in report()");
     if(n == null) throw new IllegalArgumentException("invalid key in report()");
@@ -464,7 +440,7 @@
     }
     
     public int guess(Key k) {
-       return guess(convert(k));
+       return guess(k.toBigInteger());
     }
    
     public int guess(BigInteger n) {
@@ -475,10 +451,10 @@
                                n = n.subtract(keyspace);
        
                // Solve for the time given key and two bounding points.
-        BigInteger i = BigInteger.valueOf(b.right.time - b.left.time)
-               .multiply(n.subtract(b.left.key))
-               .divide(b.right.key.subtract(b.left.key))
-               .add(BigInteger.valueOf(b.left.time));
+        BigInteger i = BigInteger.valueOf(b.right.getTime() - b.left.getTime())
+               .multiply(n.subtract(b.left.getKey()))
+               .divide(b.right.getKey().subtract(b.left.getKey()))
+               .add(BigInteger.valueOf(b.left.getTime()));
        
         // 2^31 microseconds is 36 minutes.
                return i.intValue();
@@ -582,7 +558,7 @@
                                        recentTimes[x] = i.readInt();
                                        if (recentTimes[x] < 0)
                                                throw new IOException("negative 
value");
-                                       byte[] b = new byte[KEYBYTES];
+                                       byte[] b = new byte[Key.KEYBYTES];
                                        i.readFully(b);
                                        recentKeys[x] = new BigInteger(1, b);
                                        if (recentKeys[x].signum() == -1)
@@ -628,21 +604,21 @@
                                o.writeInt(recentTimes[i]);
                                byte[] b;
                                if (recentKeys[i] == null) {
-                                       b = new byte[KEYBYTES];
-                                       for (int ii = 0; ii < KEYBYTES; ii++)
+                                       b = new byte[Key.KEYBYTES];
+                                       for (int ii = 0; ii < Key.KEYBYTES; ii++)
                                                b[ii] = 0;
                                } else {
                                        b = recentKeys[i].toByteArray();
-                                       if (b.length > KEYBYTES + 1)
+                                       if (b.length > Key.KEYBYTES + 1)
                                                throw new IllegalStateException("Key 
too long in serializing: " + b.length);
                                }
-                               if (b.length < KEYBYTES) {
-                                       int skip = KEYBYTES - b.length;
+                               if (b.length < Key.KEYBYTES) {
+                                       int skip = Key.KEYBYTES - b.length;
                                        for (int x = 0; x < skip; x++)
                                                o.writeByte(0);
                                        o.write(b);
                                } else
-                                       o.write(b, b.length - KEYBYTES, KEYBYTES);
+                                       o.write(b, b.length - Key.KEYBYTES, 
Key.KEYBYTES);
                                // in case of zero padding
                        }
                }
@@ -669,7 +645,8 @@
                         * @see java.util.Enumeration#hasMoreElements()
                         */
                        public boolean hasMoreElements() {
-                               return location < RECENT_LENGTH;
+                               return (location < RECENT_LENGTH &&
+                                               recentKeys[location]!= null); //Stop 
early if the history hasn't yet filled up
                        }
 
                        /* (non-Javadoc)
@@ -793,313 +770,4 @@
                        return formatFromRaw(highestRaw(),type);
                }
           }
-       
-       protected class RoutingPointStore {
-               RoutingPoint points[];
-               final RoutingPointStore.RoutingPointKeySorter ms = new 
RoutingPointKeySorter();
-               
-               //Represents a point in a routing graph
-               //Is the fundamental storage item of the RoutingStore
-               class RoutingPoint {
-                       BigInteger key;
-                       int time;
-                       double sensitivity;
-                       RoutingPoint() {
-                               key = null;
-                               time = 0;
-                               sensitivity = 0;
-                       }
-                       RoutingPoint(BigInteger key, int time, double sensitivity) {
-                               this.key = key;
-                               this.time = time;
-                               this.sensitivity = sensitivity;
-                       }
-               }
-               //A pair of two neighbouring RoutingPoints, including information on 
wheter or not
-               //there is a keyspace wrap between them (right-key actually a larger 
value than left-key)
-               class NeighbourRoutingPointPair {
-                       RoutingPointStore.RoutingPoint left, right; //The key before 
and the key after the supplied key
-                       boolean includesKeyspaceWrap; //Wheter or not a keyspace wrap 
is actually between the two RoutingPoints
-                       int nPos; //TODO:Get rid of this one. The position of the key 
that before and after is just that.
-               }
-               
-               //Sorts the store in order of the RoutingPoint keys.
-               private final class RoutingPointKeySorter implements Sortable {
-                       public final int compare(int index1, int index2) {
-                               return 
points[index1].key.compareTo(points[index2].key);
-                       }
-
-                       public final void swap(int index1, int index2) {
-                               RoutingPoint p = points[index1];
-                               points[index1] = points[index2];
-                               points[index2] = p;
-                       }
-
-                       public final int size() {
-                               return length();
-                       }
-               }
-
-               //Create fresh routing store with 'accuracy' number of default-valued 
RoutingPoints
-               public RoutingPointStore(int accuracy) {
-                       points = new RoutingPoint[accuracy];
-                       for (int x = 0; x < points.length; x++) {
-                               points[x] = new RoutingPoint();
-                       }
-               }
-
-               //Create a store by reading a serialization
-               public RoutingPointStore(DataInputStream i) throws IOException {
-                       int accuracy = i.readInt();
-                       if (accuracy < 0)
-                               throw new IOException("failed read");
-                       if (accuracy == 0 || accuracy > MAX_ACCURACY) // seems 
reasonable bounds
-                               throw new IOException("Invalid accuracy word " + 
accuracy);
-                       points = new RoutingPoint[accuracy];
-                       
-                       
-                       BigInteger prev = BigInteger.ZERO;
-
-                       for (int x = 0; x < points.length; x++) {
-                               int time = i.readInt();
-                               //time[x] = i.readInt();
-                               if (time < 0)
-                                       throw new IOException("negative value");
-                               byte[] b = new byte[KEYBYTES];
-                               i.readFully(b);
-                               BigInteger key = new BigInteger(1, b);
-                               if (key.signum() == -1)
-                                       throw new IOException("negative key");
-                               if (key.compareTo(keyspace) == 1)
-                                       throw new IOException("exceeded keyspace");
-                               if (key.compareTo(prev) == -1)
-                                       throw new IOException("smaller than prev");
-                               prev = key;
-                               double sensitivity = i.readDouble();
-                               points[x] = new RoutingPoint(key,time,sensitivity);
-                       }
-               }
-               //TODO: Documentation
-               public RoutingPointStore(Key k, int high, int low, int accuracy) {
-                       this(accuracy); 
-                       if (high < 0 || low < 0)
-                               throw new IllegalArgumentException("negative high " + 
high + " or low " + low);
-                       // Center on k
-                       // b = keyspace / accuracy
-                       // c = k % c
-                       // Then set keys as in monadic constructor, except adding k
-                       BigInteger a = keyspace.subtract(BigInteger.ONE);
-                       BigInteger b = a.divide(BigInteger.valueOf(accuracy));
-                       BigInteger ik = convert(k);
-                       BigInteger[] dr = ik.divideAndRemainder(b);
-                       BigInteger c = dr[1]; // remainder. positive!
-                       if (c.signum() < 0)
-                               throw new IllegalStateException("argh");
-                       int kOffset = dr[0].intValue();
-                       for (int i = 0; i < accuracy; i++) {
-                               points[i].key = c;
-                               c.add(b);
-                       }
-                       // Now the times
-                       int val = high;
-                       int valStep = (high - low) / accuracy;
-                       for (int i = 0; i < accuracy; i++) {
-                               int offset = (kOffset + i) % accuracy;
-                               points[offset].time = val;
-                               if (i <= accuracy / 2)
-                                       val -= valStep;
-                               else
-                                       val += valStep;
-                       }
-                       //TODO: What about the sensitivities?
-               }
-
-               //Returns the offset of the biggest key that's still less than n.
-               final synchronized int search(BigInteger n) {
-                       int mid, low = 0, high = points.length - 1;
-
-                       for (;;) {
-                               mid = (high + low) >> 1;
-                               int i = points[mid].key.compareTo(n);
-                               if (i <= 0 && points[mid+1].key.compareTo(n) > 0)
-                                       return mid;
-                               if (i > 0)
-                                       high = mid;
-                               else
-                                       low = mid + 1;
-                               if (low == high)
-                                       return low;
-                       }
-               }
-
-               //Sets all times to the supplied value
-               private synchronized void setAllTimes(int newtime) {
-                       for (int i = 0; i < points.length; i++) {
-                               points[i].time = newtime;
-                       }
-               }
-               
-               //Returns the RoutingPoint at the position 'index' in the store
-               synchronized RoutingPoint get(int index) {
-                       return points[index];
-               }
-               
-               synchronized void set(int index, RoutingPoint value) {
-                       points[index] = value;
-               }
-               //Finds the position of the first key in the store, before the 
position 'startAt', that is smaller than n
-               //Returns -1 if no such key is present in the store
-               protected synchronized int findFirstSmaller_reverse(BigInteger n, int 
startAt) {
-                       while (points[startAt].key.compareTo(n) == 1) {
-                               startAt--;
-                               if (startAt < 0)
-                                       return -1;
-                       }
-                       return startAt;
-               }
-               //Finds the position of the first key in the store, after the position 
'startAt', that is larger than n
-               //Returns -1 if no such key is present in the store
-               protected synchronized int findFirstLarger(BigInteger n, int startAt) {
-                       while (points[startAt].key.compareTo(n) == -1) {
-                               startAt++;
-                               if (startAt >= points.length)
-                                       return -1;
-                       }
-                       return startAt;
-               }
-
-               int getDataLength() {
-                       return 4 + points.length * (4 + KEYBYTES);
-               }
-               
-               //Returns the number of items in the store
-               int length() {
-                       return points.length;
-               }
-               public synchronized void dumpLog() {
-                       if (Core.logger.shouldLog(Logger.MINOR, this)) {
-                               StringBuffer sb = new StringBuffer();
-                               for (int x = 0; x < points.length; x++) {
-                                       sb.append(points[x].key.toString(16));
-                                       sb.append(": ");
-                                       int t = points[x].time;
-                                       sb.append(Integer.toString(t));
-                                       if (t < 0)
-                                               Core.logger.log(this, "time[" + x + 
"]=" + t + " - NEGATIVE (" + this +")", Logger.ERROR);
-                                       sb.append("\n");
-                               }
-                               Core.logger.log(this, "Dump of " + this +": \n" + 
sb.toString(), Logger.MINOR);
-                       } else {
-                               //Do only the sanity check if we wont log the contents 
of the estimator
-                               for (int x = 0; x < points.length; x++) {
-                                       int t = points[x].time;
-                                       if (t < 0)
-                                               Core.logger.log(this, "time[" + x + 
"]=" + t + " - NEGATIVE (" + this +")", Logger.ERROR);
-                               }
-                       }
-               }
-               synchronized void dumpHtml(PrintWriter pw) {
-                       for (int x = 0; x < points.length; x++) {
-                               pw.println("<tr><td>" + x + "</td><td>" + 
points[x].key.toString(16) + "</td><td>" + points[x].time + "</td><td>" + 
points[x].sensitivity + "</td></tr>");
-                               if (points[x].time < 0)
-                                       Core.logger.log(this, "time[" + x + "]=" + 
points[x].time + " - NEGATIVE (" + this +")", Logger.ERROR);
-                       }
-               }
-               //Returns the value (time) of the highest-valued RoutingPoint
-               public synchronized long highestRaw() {
-                       int highest = 0;
-                       for (int x = 0; x < points.length; x++) {
-                               highest = Math.max(highest,points[x].time);
-                       }
-                       return highest;
-               }
-               //Returns the value (time) of the lowest-valued RoutingPoint
-               public synchronized long lowestRaw() {
-                       int lowest = Integer.MAX_VALUE;
-                       for (int x = 0; x < points.length; x++) {
-                               lowest = Math.min(lowest,points[x].time);
-                       }
-                       return lowest;
-               }
-               public synchronized void print() {
-                       for (int i = 0; i < points.length; i++)
-                               System.out.println(i + ":\t" + points[i].key + "\t" + 
points[i].time);
-               }
-               //Sorts the RoutingStore in order of its RoutingPoint keys
-               protected synchronized void sortByKey() {
-                       if (logDEBUG)
-                               Core.logger.log(this, "Reordering keys", Logger.DEBUG);
-                       dumpLog();
-                       // We cannot simply find the lowest value and then shift,
-                       // Becuase we are not using anything like strict gravity
-                       // We move the first key 1/2 the distance closer, the second 
1/4 its distance
-                       // closer, the third 1/8 its distance closer etc
-                       // They get reordered!
-                       QuickSorter.quickSort(ms);
-                       dumpLog();
-               }
-
-               //Serializes the store to the supplied DataOutputStream
-               public synchronized void writeTo(DataOutputStream o) throws 
IOException {
-                       logDEBUG = Core.logger.shouldLog(Logger.DEBUG, this);
-                       if (logDEBUG)
-                               logDEBUG("Serializing store to disk, accuracy " + 
points.length);
-                       o.writeInt(points.length);
-                       for (int i = 0; i < points.length; i++) {
-                               o.writeInt(points[i].time);
-                               byte[] b = points[i].key.toByteArray();
-                               if (b.length > KEYBYTES + 1)
-                                       throw new IllegalStateException("Key too long 
in serializing: " + b.length);
-                               if (b.length < KEYBYTES) {
-                                       int skip = KEYBYTES - b.length;
-                                       for (int x = 0; x < skip; x++)
-                                               o.writeByte(0);
-                                       o.write(b);
-                               } else
-                                       o.write(b, b.length - KEYBYTES, KEYBYTES);
-                               // in case of zero padding
-                               o.writeDouble(points[i].sensitivity);
-                       }
-               }
-
-               //Returns the RoutingPoint which has the highest key
-               private RoutingPoint lastPoint() {
-                       return get(points.length - 1);
-               }
-               //Returns the RoutingPoint which has the lowest key
-               private RoutingPoint firstPoint() {
-                       return get(0);
-               }
-               //distributes the keys evenly throughout all of the keyspace
-               private synchronized void distributeKeysEvenly() {
-                       BigInteger a = keyspace.subtract(BigInteger.ONE);
-                       BigInteger b = a.divide(BigInteger.valueOf(points.length));
-                       for (int i = points.length; --i >= 0; a = a.subtract(b))
-                               points[i].key = a;
-               }
-
-               //Locates the RoutingPoints who are keywise located right before and 
right after the supplied BigInteger
-               //Handles keyspace wrap situations. The returned class contains 
information wheter or not a wrap occurred
-               synchronized NeighbourRoutingPointPair 
findKeyBeforeAndAfter(BigInteger n) {
-                       NeighbourRoutingPointPair retval = new 
NeighbourRoutingPointPair();
-                       int pos = store.search(n);
-
-                       retval.nPos = pos;
-                       //Is it off the keyspace, either to the left or to the right...
-                       if ((pos == 0 && n.compareTo(store.firstPoint().key) < 0) || 
(pos == store.length() - 1)) {
-                               // Off the end/beginning
-                               // Doesn't matter which
-                               retval.includesKeyspaceWrap = true;
-                               pos = store.length() - 1;
-                               //Yes, beforeKey should be negative
-                               retval.left = new 
RoutingPoint(store.lastPoint().key.subtract(keyspace), points[pos].time, 
points[pos].sensitivity);
-                               retval.right = get(0);
-                       } else {//else in the middle
-                               retval.includesKeyspaceWrap = false;
-                               retval.left = get(pos);
-                               retval.right = get(pos+1);
-                       }
-                       return retval;
-               }
-       }
 }

Index: FFTTimeEstimator.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/node/rt/FFTTimeEstimator.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -w -r1.6 -r1.7
--- FFTTimeEstimator.java       31 Oct 2003 19:38:21 -0000      1.6
+++ FFTTimeEstimator.java       3 Nov 2003 08:04:54 -0000       1.7
@@ -22,7 +22,7 @@
 
     //overriden to use FFT on all points
     public synchronized void report (Key k, int usec) {
-       BigInteger n = convert(k);
+       BigInteger n = k.toBigInteger();
        recent.report(n,usec);
        
        

_______________________________________________
cvs mailing list
[EMAIL PROTECTED]
http://dodo.freenetproject.org/cgi-bin/mailman/listinfo/cvs

Reply via email to