Update of /cvsroot/freenet/freenet/src/freenet/node/rt
In directory sc8-pr-cvs1:/tmp/cvs-serv14480/src/freenet/node/rt
Modified Files:
ResponseTimeEstimator.java
Log Message:
Initial version of the RoutingPointStore. ResponseTimeEstimator now handles the
routing calculations whilst RoutingPointStore manages the storage of the RoutingPoints.
Index: ResponseTimeEstimator.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/node/rt/ResponseTimeEstimator.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -w -r1.23 -r1.24
--- ResponseTimeEstimator.java 1 Nov 2003 11:50:55 -0000 1.23
+++ ResponseTimeEstimator.java 1 Nov 2003 20:01:39 -0000 1.24
@@ -3,6 +3,7 @@
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;
@@ -35,12 +36,13 @@
// }
public class ResponseTimeEstimator implements TimeEstimator {
- BigInteger key[];
- int time[];
- double sensitivity[];
+ //BigInteger key[];
+ //int time[];
+ //double sensitivity[];
protected static final double SENSITIVITY_MAX = 10.0;
protected RecentReports recent;
+ protected RoutingPointStore store;
static final int KEYBYTES = 23,
TIMEBYTES = 4,
@@ -54,68 +56,29 @@
boolean logDEBUG = true;
public int getDataLength() {
- return 4 + key.length * (4 + KEYBYTES);
+ return store.getDataLength();
}
public ResponseTimeEstimator(DataInputStream i) throws IOException {
int version = i.readInt();
if(version != 1) throw new IOException("unrecognized version "+i);
- 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);
- key = new BigInteger[accuracy];
- time = new int[accuracy];
- sensitivity = new double[accuracy];
- BigInteger prev = BigInteger.ZERO;
- for(int x = 0; x<accuracy;x++) {
- time[x] = i.readInt();
- if(time[x] < 0) throw new IOException("negative value");
- byte[] b = new byte[KEYBYTES];
- i.readFully(b);
- key[x] = new BigInteger(1, b);
- if(key[x].signum() == -1) throw new IOException("negative key");
- if(key[x].compareTo(keyspace) == 1)
- throw new IOException("exceeded keyspace");
- if(key[x].compareTo(prev) == -1)
- throw new IOException("smaller than prev");
- prev = key[x];
- sensitivity[x] = i.readDouble();
- }
+ store = new RoutingPointStore(i);
try {
recent = new RecentReports(i);
} catch (IOException e) {
Core.logger.log(this, "Failed reading estimator report history from
InputStream, using empty history",e, Logger.ERROR);
recent = new RecentReports();
- // Not fatal - probably upgrading
+ // Not fatal - possibly upgrading
}
logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
}
- public void writeTo(DataOutputStream o) throws IOException {
- logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
- if(logDEBUG) logDEBUG("Serializing to disk, accuracy "+time.length);
+ public synchronized void writeTo(DataOutputStream o) throws IOException {
o.writeInt(1); // current version. Using negative numbers for compatibility.
- o.writeInt(time.length);
- synchronized(this) {
- for(int i=0;i<time.length;i++) {
- o.writeInt(time[i]);
- byte[] b = key[i].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(sensitivity[i]);
- }
+ store.writeTo(o);
recent.writeTo(o);
}
- }
private void logMINOR(String s) {
if(Core.logger.shouldLog(Logger.MINOR,this))
@@ -147,88 +110,24 @@
public ResponseTimeEstimator(int initTime, int accuracy) {
this(accuracy);
if(initTime < 0) throw new IllegalArgumentException("negative initTime");
- setAllTimes(initTime);
- }
-
- //Sets all times to the supplied value
- private void setAllTimes(int newtime) {
- for(int i=0;i<time.length;i++) {
- time[i] = newtime;
- }
+ store.setAllTimes(initTime);
}
public ResponseTimeEstimator(Key k, int high, int low, int accuracy) {
- key = new BigInteger[accuracy];
- time = new int[accuracy];
- sensitivity = new double[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++) {
- key[i] = 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;
- time[offset] = val;
- if(i <= accuracy / 2)
- val -= valStep;
- else
- val += valStep;
- }
+ store = new RoutingPointStore(k,high,low,accuracy);
recent = new RecentReports();
}
public ResponseTimeEstimator(int accuracy) {
- key = new BigInteger[accuracy];
- time = new int[accuracy];
- sensitivity = new double[accuracy];
+ store = new RoutingPointStore(accuracy);
// Let's evenly distribute the keys across the whole
// keyspace and leave the time values at zero.
- dristributeKeysEvenly();
+ store.distributeKeysEvenly();
+ store.setAllTimes(0);
recent = new RecentReports();
}
- //distributes the keys evenly all through the keyspace
- private void dristributeKeysEvenly() {
- BigInteger a = keyspace.subtract(BigInteger.ONE);
- BigInteger b = a.divide(BigInteger.valueOf(key.length));
- for (int i = key.length; --i >= 0; a = a.subtract(b))
- key[i] = a;
- }
-
- // Return offset of the biggest key that's still less than n.
- final int search(BigInteger n) {
- int mid, low = 0, high = key.length - 1;
-
- for (;;) {
- mid = (high + low) >> 1;
- int i = key[mid].compareTo(n);
- if (i <= 0 && key[mid + 1].compareTo(n) > 0)
- return mid;
- if (i > 0)
- high = mid;
- else
- low = mid + 1;
- if (low == high)
- return low;
- }
- }
// Interpret key as value between 0 and 2^183.
final BigInteger convert(Key k) {
@@ -246,87 +145,18 @@
return new BigInteger(1, b);
}
- protected final class MySorter implements Sortable {
- public final int compare(int index1, int index2) {
- return key[index1].compareTo(key[index2]);
- }
-
- public final void swap(int index1, int index2) {
- BigInteger bi = key[index1];
- key[index1] = key[index2];
- key[index2] = bi;
- }
-
- public final int size() {
- return key.length;
- }
- }
-
- final MySorter ms = new MySorter();
-
- protected void orderKeys() {
- 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();
- }
-
- class keyTimeSens{
- BigInteger key;
- int time;
- double sensitivity;
- keyTimeSens(BigInteger key, int time, double sensitivity){
- this.key = key;
- this.time = time;
- this.sensitivity = sensitivity;
- }
- }
- keyTimeSens get(int index){
- return new keyTimeSens(key[index],time[index],sensitivity[index]);
- }
- void set(int index,keyTimeSens value){
- key[index] = value.key;
- time[index] = value.time;
- sensitivity[index] = value.sensitivity;
- }
static final BigDecimal DEC_ONE = new BigDecimal(1.0);
static final BigInteger THREE = BigInteger.valueOf(3);
static final BigInteger FOUR = BigInteger.valueOf(4);
- //Reversively finds the position of the first key in the store, after the
position 'startAt', that is smaller than n
- //Returns -1 if no such key is present in the store
- protected int findFirstSmaller_reverse(BigInteger n, int startAt){
- while (key[startAt].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 int findFirstLarger(BigInteger n, int startAt){
- while (key[startAt].compareTo(n) == -1) {
- startAt++;
- if (startAt >= key.length)
- return -1;
- }
- return startAt;
- }
protected synchronized int reportDecreasing(BigInteger lowerBound, BigInteger
upperBound, BigInteger center, int usec, int initialSteps, int lowerBoundPos, int
upperBoundPos) {
if (logDEBUG)
Core.logger.log(this, "reportDecreasing(" +
lowerBound.toString(16) + "," + upperBound.toString(16) + "," + center.toString(16) +
"," + initialSteps + "," + lowerBoundPos + "," + upperBoundPos + ")", new
Exception("debug"), Logger.DEBUG);
- dumpLog();
- upperBoundPos = Math.min(upperBoundPos,key.length - 1);
- lowerBoundPos = Math.min(lowerBoundPos,key.length - 1);
+ store.dumpLog();
+ upperBoundPos = Math.min(upperBoundPos,store.length() - 1);
+ lowerBoundPos = Math.min(lowerBoundPos,store.length() - 1);
lowerBoundPos = Math.max(lowerBoundPos,0);
upperBoundPos = Math.max(upperBoundPos,0);
if (usec < 0)
@@ -336,21 +166,21 @@
// inc shiftAmount each time we move a point
int shiftAmount = initialSteps;
- upperBoundPos = findFirstSmaller_reverse(upperBound,upperBoundPos);
+ upperBoundPos =
store.findFirstSmaller_reverse(upperBound,upperBoundPos);
if (upperBoundPos < 0) return initialSteps;
- lowerBoundPos = findFirstLarger(lowerBound,lowerBoundPos);
+ lowerBoundPos = store.findFirstLarger(lowerBound,lowerBoundPos);
if (lowerBoundPos < 0) return initialSteps;
if (lowerBoundPos > upperBoundPos)
return initialSteps;
for (int i = lowerBoundPos; i <= upperBoundPos; i++) {
- keyTimeSens k = get(i);
+ RoutingPointStore.RoutingPoint k = store.get(i);
if (k.time < 0)
Core.logger.log(this, "time[" + i + "] = " + k.time +
" - NEGATIVE TIME!", Logger.ERROR);
if (logDEBUG)
Core.logger.log(this, "Trying key[" + i + "]: " +
k.key.toString(16) + "," + k.time, Logger.DEBUG);
- ensureSensitivityBelowMax(i);
+ k.sensitivity = Math.min(k.sensitivity,SENSITIVITY_MAX);
//double sens = sensitivity[i];
BigInteger diff = handleKeyspaceWrap(k.key.subtract(center));
// Result = old position + ((old position * sensitivity) /
(sensitivity + 1)
@@ -374,7 +204,7 @@
int timediff = usec - k.time;
if (logDEBUG)
- Core.logger.log(this, "usec=" + usec + ", time[" + i +
"]=" + time[i] + ", timediff=" + timediff, Logger.DEBUG);
+ Core.logger.log(this, "usec=" + usec + ", time[" + i +
"]=" + k.time + ", timediff=" + timediff, Logger.DEBUG);
double fracTimediff = (double) timediff;
if (logDEBUG)
Core.logger.log(this, "fracTimediff=" + fracTimediff,
Logger.DEBUG);
@@ -386,17 +216,17 @@
Core.logger.log(this, "timediff now = " + timediff,
Logger.DEBUG);
timediff = (int) ((((long) timediff) * 3) / 4);
if (logDEBUG)
- Core.logger.log(this, "time[" + i + "] = " + time[i] +
", timediff = " + timediff, Logger.DEBUG);
+ Core.logger.log(this, "time[" + i + "] = " + k.time +
", timediff = " + timediff, Logger.DEBUG);
k.time += timediff;
if (logDEBUG)
- Core.logger.log(this, "key[" + i + "] now: " +
key[i].toString(16) + "," + time[i], Logger.DEBUG);
+ 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);
- set(i,k);
+ store.set(i,k);
shiftAmount++;
}
- dumpLog();
+ store.dumpLog();
return shiftAmount;
}
@@ -425,9 +255,9 @@
upperBound.toString(16)+","+center.toString(16)+","+
initialSteps+","+lowerBoundPos+","+upperBoundPos+")",
new Exception("debug"), Logger.DEBUG);
- dumpLog();
- upperBoundPos = Math.min(upperBoundPos,key.length - 1);
- lowerBoundPos = Math.min(lowerBoundPos,key.length - 1);
+ store.dumpLog();
+ upperBoundPos = Math.min(upperBoundPos,store.length() - 1);
+ lowerBoundPos = Math.min(lowerBoundPos,store.length() - 1);
lowerBoundPos = Math.max(lowerBoundPos,0);
upperBoundPos = Math.max(upperBoundPos,0);
if(usec < 0) throw new IllegalArgumentException("usec "+usec+" negative!");
@@ -436,15 +266,15 @@
// inc shiftAmount each time we move a point
int shiftAmount = initialSteps;
- upperBoundPos = findFirstSmaller_reverse(upperBound,upperBoundPos);
+ upperBoundPos = store.findFirstSmaller_reverse(upperBound,upperBoundPos);
if (upperBoundPos < 0) return initialSteps;
- lowerBoundPos = findFirstLarger(lowerBound,lowerBoundPos);
+ lowerBoundPos = store.findFirstLarger(lowerBound,lowerBoundPos);
if (lowerBoundPos < 0)return initialSteps;
if(lowerBoundPos > upperBoundPos) return initialSteps;
for(int i=upperBoundPos;i>=lowerBoundPos;i--) {
- keyTimeSens k = get(i);
+ RoutingPointStore.RoutingPoint k = store.get(i);
if(logDEBUG)
Core.logger.log(this, "Trying key["+i+"]: "+
k.key.toString(16)+","+k.time,
@@ -452,7 +282,7 @@
if(k.time < 0)
Core.logger.log(this, "time["+i+"] = "+k.time+
" - NEGATIVE TIME!", Logger.ERROR);
- ensureSensitivityBelowMax(i);
+ k.sensitivity = Math.min(k.sensitivity,SENSITIVITY_MAX);
//double sens = sensitivity[i];
BigInteger diff = handleKeyspaceWrap(center.subtract(k.key));
BigDecimal fracDiff = new BigDecimal(diff);
@@ -477,16 +307,13 @@
if(k.time < 0)
Core.logger.log(this, "time["+i+"] = "+k.time+
" - NEGATIVE TIME!", Logger.ERROR);
- set(i,k);
+ store.set(i,k);
}
- dumpLog();
+ store.dumpLog();
return shiftAmount;
}
- //Ensures that the sensitivity at the given position is below the allowed
threshold
- private void ensureSensitivityBelowMax(int index) {
- if(sensitivity[index] > SENSITIVITY_MAX)
- sensitivity[index] = SENSITIVITY_MAX;
- }
+
+
public synchronized void report(Key k, int usec) {
logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
@@ -496,13 +323,13 @@
if(n == null) throw new IllegalArgumentException("invalid key in report()");
recent.report(n,usec);
- int pos = search(n);
+ int pos = store.search(n);
if(logDEBUG)
Core.logger.log(this, "report("+n.toString(16)+","+usec+")",
Logger.DEBUG);
- dumpLog();
+ store.dumpLog();
int x = n.compareTo(halfkeyspace);
if(x == 1) {
if(logDEBUG)
@@ -512,11 +339,11 @@
// n ... keyspace, 0 ... n-halfkeyspace moved left
// n-halfkeyspace ... n moved right
BigInteger m = n.subtract(halfkeyspace);
- int mpos = search(m);
- int steps = reportDecreasing(n, keyspace, n, usec, 0, pos+1, key.length-1);
+ int mpos = store.search(m);
+ int steps = reportDecreasing(n, keyspace, n, usec, 0, pos+1,
store.length()-1);
reportDecreasing(BigInteger.ZERO, m, n, usec, steps, 0, mpos);
- reportIncreasing(m, n, n, usec, 0, mpos+1, key.length-1);
- orderKeys(); // if the edge wraps, over the next section, then we
orderKeys before the next section is done, we are stuffed
+ reportIncreasing(m, n, n, usec, 0, mpos+1, store.length()-1);
+ store.sortByKey(); // if the edge wraps, over the next section, then we
orderKeys before the next section is done, we are stuffed
} else if(x == -1) {
if(logDEBUG)
Core.logger.log(this, "Below half keyspace",
@@ -526,22 +353,22 @@
// 0 ... n moved right
// n+halfkeyspace .. keyspace moved right
BigInteger c = n.add(halfkeyspace);
- int cpos = search(c);
+ int cpos = store.search(c);
reportDecreasing(n, c, n, usec, 0, pos+1, cpos);
int steps = reportIncreasing(BigInteger.ZERO, n, n, usec, 0, 0, pos);
- reportIncreasing(c, keyspace, n, usec, steps, cpos+1, key.length-1);
- orderKeys();
+ reportIncreasing(c, keyspace, n, usec, steps, cpos+1, store.length()-1);
+ store.sortByKey();
} else {
if(logDEBUG)
Core.logger.log(this, "Dead on half keyspace",
Logger.DEBUG);
// We are in the exact center
- int mpos = search(halfkeyspace);
+ int mpos = store.search(halfkeyspace);
reportIncreasing(BigInteger.ZERO, halfkeyspace, halfkeyspace, usec,
0, 0, mpos);
reportDecreasing(halfkeyspace, keyspace, halfkeyspace, usec,
- 0, mpos+1, key.length-1);
- orderKeys();
+ 0, mpos+1, store.length()-1);
+ store.sortByKey();
}
if(logDEBUG)
Core.logger.log(this, "report("+n.toString(16)+","+usec+") completed",
@@ -556,28 +383,6 @@
// }
}
- public void dumpLog() {
- if (Core.logger.shouldLog(Logger.MINOR, this)) {
- StringBuffer sb = new StringBuffer();
- for (int x = 0; x < key.length; x++) {
- sb.append(key[x].toString(16));
- sb.append(": ");
- int t = time[x];
- 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 < key.length; x++) {
- int t = time[x];
- if (t < 0)
- Core.logger.log(this, "time[" + x + "]=" + t +
" - NEGATIVE (" + this +")", Logger.ERROR);
- }
- }
- }
public double guessTime(Key k) {
return (double)guess(k); // resolution 1ms
@@ -663,47 +468,17 @@
}
public synchronized int guess(BigInteger n) {
- logDEBUG = Core.logger.shouldLog(Logger.DEBUG,this);
- int pos = search(n);
+ RoutingPointStore.NeighbourRoutingPointPair b =
store.findKeyBeforeAndAfter(n);
- // It's off the charts...
- //if (pos == 0 && n.compareTo(key[0]) < 0 || pos == key.length - 1)
- //return time[pos];
-
- int npos;
- BigInteger beforeKey, afterKey;
- int beforeTime, afterTime;
- int opos = pos;
- if ((pos == 0 && n.compareTo(key[0]) < 0) ||
- (pos == key.length - 1)) {
- // Off the end/beginning
- // Doesn't matter which
- pos = key.length -1;
- npos = 0;
- beforeTime = time[pos];
- afterTime = time[npos];
- BigInteger a = keyspace;
- beforeKey = key[key.length-1].
- subtract(a);
- // Yes, beforeKey should be negative
- if(opos == key.length -1)
- n = n.subtract(a);
- afterKey = key[0];
- } else {
- // In the middle
- //pos = pos;
- npos = pos + 1;
- beforeTime = time[pos];
- afterTime = time[npos];
- beforeKey = key[pos];
- afterKey = key[npos];
- }
+ if(b.includesKeyspaceWrap)
+ if(b.nPos == store.length() -1)
+ n = n.subtract(keyspace);
// Solve for the time given key and two bounding points.
- BigInteger i = BigInteger.valueOf(afterTime - beforeTime)
- .multiply(n.subtract(beforeKey))
- .divide(afterKey.subtract(beforeKey))
- .add(BigInteger.valueOf(beforeTime));
+ 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));
//System.out.println("\n"+key[pos]+"="+time[pos]);
//System.out.println(n+"="+i.intValue());
@@ -738,11 +513,6 @@
}
*/
- public void print() {
- for (int i = 0; i < key.length; i++)
- System.out.println(i+":\t"+key[i]+"\t"+time[i]);
- }
-
public static TimeEstimatorFactory factory() {
return factory(DEFAULT_ACCURACY);
}
@@ -751,8 +521,7 @@
return new ResponseTimeEstimatorFactory(accuracy);
}
- public static class ResponseTimeEstimatorFactory
- implements TimeEstimatorFactory {
+ public static class ResponseTimeEstimatorFactory implements TimeEstimatorFactory {
int accuracy;
public ResponseTimeEstimatorFactory(int accuracy) {
this.accuracy = accuracy;
@@ -763,8 +532,7 @@
}
public TimeEstimator create(Key k, long high, long low) {
- return new ResponseTimeEstimator(k, convertTime(high),
- convertTime(low), accuracy);
+ return new ResponseTimeEstimator(k, convertTime(high),
convertTime(low), accuracy);
}
public TimeEstimator createZero() {
@@ -772,20 +540,19 @@
}
public TimeEstimator createInitTransfer(double initRate) {
- return new ResponseTimeEstimator(convertRate(initRate),
- accuracy);
+ return new ResponseTimeEstimator(convertRate(initRate),
accuracy);
}
}
public static void main(String[] args) {
Random r = new Random();
ResponseTimeEstimator rte = new ResponseTimeEstimator(1024);
- rte.print();
+ rte.store.print();
byte[] b = new byte[5];
r.nextBytes(b);
Key k = new Key(b);
rte.report(k, 64);
- rte.print();
+ rte.store.print();
/*
for (int i = 0; i < 1000; i++) {
rte.report(new Key(r), r.nextInt(Integer.MAX_VALUE));
@@ -810,19 +577,11 @@
}
public long highestRaw() {
- int highest = 0;
- for(int x=0;x<time.length;x++) {
- highest = Math.max(time[x],highest);
- }
- return highest;
+ return store.highestRaw();
}
public long lowestRaw() {
- int lowest = Integer.MAX_VALUE;
- for(int x=0;x<time.length;x++) {
- lowest = Math.min(time[x],lowest);
- }
- return lowest;
+ return store.lowestRaw();
}
//A class for keeping track of the recent reports that has come in to the
Estimator
protected static class RecentReports {
@@ -965,14 +724,8 @@
public void dumpHtml(java.io.PrintWriter pw) throws IOException {
pw.println("<table border=\"0\">");
- for(int x=0;x<key.length;x++) {
- pw.println("<tr><td>"+x+"</td><td>"+key[x].toString(16)+
- "</td><td>"+time[x]+"</td><td>"+sensitivity[x]+
- "</td></tr>");
- if(time[x] < 0)
- Core.logger.log(this, "time["+x+"]="+time[x]+
- " - NEGATIVE ("+this+")",
Logger.ERROR);
- }
+ store.dumpHtml(pw);
+
pw.println("<tr><td>Maximum</td><td colspan=\"2\">"+
keyspace.toString(16)+
"</td></tr>");
@@ -993,7 +746,7 @@
public String formatFromRaw(long x, int type) {
if(x < 0) {
- dumpLog();
+ store.dumpLog();
throw new IllegalArgumentException("negative!");
}
if(type == TIME) return Long.toString(x)+"ms";
@@ -1076,8 +829,312 @@
public String highestString(int type) {
return formatFromRaw(highestRaw(),type);
}
+ }
+ protected class RoutingPointStore {
+ BigInteger key[];
+ double sensitivity[];
+ int time[];
+ 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(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 key[index1].compareTo(key[index2]);
+ }
+
+ public final void swap(int index1, int index2) {
+ BigInteger bi = key[index1];
+ key[index1] = key[index2];
+ key[index2] = bi;
+ }
+
+ public final int size() {
+ return length();
+ }
+ }
+
+ //Create fresh, empty routing store with space for 'accuracy'
RoutingPoints
+ public RoutingPointStore(int accuracy) {
+ key = new BigInteger[accuracy];
+ time = new int[accuracy];
+ sensitivity = new double[accuracy];
+ }
+
+ //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);
+
+ key = new BigInteger[accuracy];
+ time = new int[accuracy];
+ sensitivity = new double[accuracy];
+
+ BigInteger prev = BigInteger.ZERO;
+
+ for (int x = 0; x < accuracy; x++) {
+ time[x] = i.readInt();
+ if (time[x] < 0)
+ throw new IOException("negative value");
+ byte[] b = new byte[KEYBYTES];
+ i.readFully(b);
+ key[x] = new BigInteger(1, b);
+ if (key[x].signum() == -1)
+ throw new IOException("negative key");
+ if (key[x].compareTo(keyspace) == 1)
+ throw new IOException("exceeded keyspace");
+ if (key[x].compareTo(prev) == -1)
+ throw new IOException("smaller than prev");
+ prev = key[x];
+ sensitivity[x] = i.readDouble();
+ }
+ }
+
+ public RoutingPointStore(Key k, int high, int low, int 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++) {
+ key[i] = 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;
+ time[offset] = val;
+ if (i <= accuracy / 2)
+ val -= valStep;
+ else
+ val += valStep;
+ }
+ }
+
+ //Returns the offset of the biggest key that's still less than n.
+ final int search(BigInteger n) {
+ int mid, low = 0, high = key.length - 1;
+
+ for (;;) {
+ mid = (high + low) >> 1;
+ int i = key[mid].compareTo(n);
+ if (i <= 0 && key[mid + 1].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 void setAllTimes(int newtime) {
+ for (int i = 0; i < time.length; i++) {
+ time[i] = newtime;
+ }
+ }
+
+ //Returns the RoutingPoint at the position 'index' in the store
+ RoutingPoint get(int index) {
+ return new RoutingPoint(key[index], time[index],
sensitivity[index]);
}
+ void set(int index, RoutingPoint value) {
+ key[index] = value.key;
+ time[index] = value.time;
+ sensitivity[index] = value.sensitivity;
+ }
+ //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 int findFirstSmaller_reverse(BigInteger n, int startAt) {
+ while (key[startAt].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 int findFirstLarger(BigInteger n, int startAt) {
+ while (key[startAt].compareTo(n) == -1) {
+ startAt++;
+ if (startAt >= key.length)
+ return -1;
+ }
+ return startAt;
+ }
+
+ int getDataLength() {
+ return 4 + key.length * (4 + KEYBYTES);
+ }
+
+ //Returns the number of items in the store
+ int length() {
+ return key.length;
+ }
+ public void dumpLog() {
+ if (Core.logger.shouldLog(Logger.MINOR, this)) {
+ StringBuffer sb = new StringBuffer();
+ for (int x = 0; x < key.length; x++) {
+ sb.append(key[x].toString(16));
+ sb.append(": ");
+ int t = time[x];
+ 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 < key.length; x++) {
+ int t = time[x];
+ if (t < 0)
+ Core.logger.log(this, "time[" + x +
"]=" + t + " - NEGATIVE (" + this +")", Logger.ERROR);
+ }
+ }
+ }
+ void dumpHtml(PrintWriter pw) {
+ for (int x = 0; x < key.length; x++) {
+ pw.println("<tr><td>" + x + "</td><td>" +
key[x].toString(16) + "</td><td>" + time[x] + "</td><td>" + sensitivity[x] +
"</td></tr>");
+ if (time[x] < 0)
+ Core.logger.log(this, "time[" + x + "]=" +
time[x] + " - NEGATIVE (" + this +")", Logger.ERROR);
+ }
+ }
+ //Returns the value (time) of the highest-valued RoutingPoint
+ public long highestRaw() {
+ int highest = 0;
+ for (int x = 0; x < time.length; x++) {
+ highest = Math.max(highest,time[x]);
+ }
+ return highest;
+ }
+ //Returns the value (time) of the lowest-valued RoutingPoint
+ public long lowestRaw() {
+ int lowest = Integer.MAX_VALUE;
+ for (int x = 0; x < time.length; x++) {
+ lowest = Math.min(lowest,time[x]);
+ }
+ return lowest;
+ }
+ public void print() {
+ for (int i = 0; i < key.length; i++)
+ System.out.println(i + ":\t" + key[i] + "\t" +
time[i]);
+ }
+ //Sorts the RoutingStore in order of its RoutingPoint keys
+ protected 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 void writeTo(DataOutputStream o) throws IOException {
+ logDEBUG = Core.logger.shouldLog(Logger.DEBUG, this);
+ if (logDEBUG)
+ logDEBUG("Serializing store to disk, accuracy " +
time.length);
+ o.writeInt(time.length);
+ for (int i = 0; i < time.length; i++) {
+ o.writeInt(time[i]);
+ byte[] b = key[i].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(sensitivity[i]);
+ }
+ }
+
+ //Returns the RoutingPoint which has the highest key
+ private RoutingPoint lastPoint() {
+ return get(key.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 void distributeKeysEvenly() {
+ BigInteger a = keyspace.subtract(BigInteger.ONE);
+ BigInteger b = a.divide(BigInteger.valueOf(key.length));
+ for (int i = key.length; --i >= 0; a = a.subtract(b))
+ key[i] = 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
+ 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()) < 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), time[pos], sensitivity[pos]);
+ retval.right = get(0);
+ } else {//else in the middle
+
+ retval.includesKeyspaceWrap = false;
+ retval.left = get(pos);
+ retval.right = get(pos+1);
+ }
+ return retval;
+ }
+ }
}
_______________________________________________
cvs mailing list
[EMAIL PROTECTED]
http://dodo.freenetproject.org/cgi-bin/mailman/listinfo/cvs