Author: toad
Date: 2008-04-02 01:29:15 +0000 (Wed, 02 Apr 2008)
New Revision: 18905
Modified:
trunk/freenet/src/freenet/client/async/BaseSingleFileFetcher.java
trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java
trunk/freenet/src/freenet/client/async/RequestCooldownQueue.java
trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
trunk/freenet/src/freenet/node/RequestScheduler.java
Log:
Fix critical bug in the cooldown queue: We MUST store the time, the key and
*the client*, otherwise if there is a collision on the time and key, which
happens right now in the splitfile code, we will end up queueing the block to
the cooldown queue and then removing it from it and never reregistering!
Modified: trunk/freenet/src/freenet/client/async/BaseSingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/BaseSingleFileFetcher.java
2008-04-02 01:08:37 UTC (rev 18904)
+++ trunk/freenet/src/freenet/client/async/BaseSingleFileFetcher.java
2008-04-02 01:29:15 UTC (rev 18905)
@@ -78,7 +78,7 @@
if(cooldownWakeupTime > now)
Logger.error(this, "Already on the
cooldown queue for "+this, new Exception("error"));
else
- cooldownWakeupTime = sched.queueCooldown(key);
+ cooldownWakeupTime = sched.queueCooldown(key,
this);
return true; // We will retry, just not yet.
See requeueAfterCooldown(Key).
} else {
schedule();
Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java
2008-04-02 01:08:37 UTC (rev 18904)
+++ trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java
2008-04-02 01:29:15 UTC (rev 18905)
@@ -558,7 +558,7 @@
offeredKeys[i].remove(key);
}
if(cooldownQueue != null)
- cooldownQueue.removeKey(key,
getter.getCooldownWakeupByKey(key));
+ cooldownQueue.removeKey(key, getter,
getter.getCooldownWakeupByKey(key));
}
/**
@@ -629,12 +629,12 @@
if(o instanceof SendableGet) {
gets = new SendableGet[] { (SendableGet) o };
if(cooldownQueue != null)
- cooldownQueue.removeKey(key,
((SendableGet)o).getCooldownWakeupByKey(key));
+ cooldownQueue.removeKey(key, (SendableGet)o,
((SendableGet)o).getCooldownWakeupByKey(key));
} else {
gets = (SendableGet[]) o;
if(cooldownQueue != null)
for(int i=0;i<gets.length;i++)
- cooldownQueue.removeKey(key,
gets[i].getCooldownWakeupByKey(key));
+ cooldownQueue.removeKey(key, gets[i],
gets[i].getCooldownWakeupByKey(key));
}
if(gets == null) return;
@@ -698,8 +698,8 @@
}
}
- public long queueCooldown(ClientKey key) {
- return cooldownQueue.add(key.getNodeKey());
+ public long queueCooldown(ClientKey key, SendableGet getter) {
+ return cooldownQueue.add(key.getNodeKey(), getter);
}
public void moveKeysFromCooldownQueue() {
Modified: trunk/freenet/src/freenet/client/async/RequestCooldownQueue.java
===================================================================
--- trunk/freenet/src/freenet/client/async/RequestCooldownQueue.java
2008-04-02 01:08:37 UTC (rev 18904)
+++ trunk/freenet/src/freenet/client/async/RequestCooldownQueue.java
2008-04-02 01:29:15 UTC (rev 18905)
@@ -4,6 +4,7 @@
package freenet.client.async;
import freenet.keys.Key;
+import freenet.node.SendableGet;
import freenet.support.Fields;
import freenet.support.Logger;
@@ -21,6 +22,8 @@
private Key[] keys;
/** times at which keys will be valid again */
private long[] times;
+ /** clients responsible for the keys */
+ private SendableGet[] clients;
/** count of keys removed from middle i.e. holes */
int holes;
/** location of first (chronologically) key */
@@ -37,6 +40,7 @@
logMINOR = Logger.shouldLog(Logger.MINOR, this);
keys = new Key[MIN_SIZE];
times = new long[MIN_SIZE];
+ clients = new SendableGet[MIN_SIZE];
holes = 0;
startPtr = 0;
endPtr = 0;
@@ -46,13 +50,13 @@
/**
* Add a key to the end of the queue. Returns the time at which it will
be valid again.
*/
- synchronized long add(Key key) {
+ synchronized long add(Key key, SendableGet client) {
long removeTime = System.currentTimeMillis() + cooldownTime;
if(removeTime < getLastTime()) {
removeTime = getLastTime();
Logger.error(this, "CLOCK SKEW DETECTED!!! Attempting
to compensate, expect things to break!");
}
- add(key, removeTime);
+ add(key, client, removeTime);
return removeTime;
}
@@ -62,7 +66,7 @@
return times[times.length-1];
}
- private synchronized void add(Key key, long removeTime) {
+ private synchronized void add(Key key, SendableGet client, long
removeTime) {
if(holes < 0) Logger.error(this, "holes = "+holes+" !!");
logMINOR = Logger.shouldLog(Logger.MINOR, this);
if(logMINOR)
@@ -75,7 +79,7 @@
if(startPtr == 0) {
// No room
expandQueue();
- add(key);
+ add(key, client);
return;
} else {
// Wrap around
@@ -88,7 +92,7 @@
if(logMINOR) Logger.minor(this, "endPtr < startPtr");
if(endPtr == startPtr - 1) {
expandQueue();
- add(key);
+ add(key, client);
return;
} else {
endPtr++;
@@ -102,6 +106,7 @@
if(logMINOR) Logger.minor(this, "Added at "+ptr+"
startPtr="+startPtr+" endPtr="+endPtr);
keys[ptr] = key;
times[ptr] = removeTime;
+ clients[ptr] = client;
return;
}
@@ -123,6 +128,7 @@
Key key = keys[startPtr];
if(key == null) {
times[startPtr] = 0;
+ clients[startPtr] = null;
startPtr++;
holes--;
if(startPtr == times.length) startPtr = 0;
@@ -135,6 +141,7 @@
}
times[startPtr] = 0;
keys[startPtr] = null;
+ clients[startPtr] = null;
startPtr++;
if(startPtr == times.length) startPtr = 0;
}
@@ -146,7 +153,7 @@
/**
* @return True if the key was found.
*/
- synchronized boolean removeKey(Key key, long time) {
+ synchronized boolean removeKey(Key key, SendableGet client, long time) {
if(time <= 0) return false; // We won't find it.
logMINOR = Logger.shouldLog(Logger.MINOR, this);
if(holes < 0) Logger.error(this, "holes = "+holes+" !!");
@@ -166,8 +173,9 @@
}
if(logMINOR) Logger.minor(this, "idx = "+idx);
if(idx < 0) return false;
- if(keys[idx] == key) {
+ if(keys[idx] == key && clients[idx] == client) {
keys[idx] = null;
+ clients[idx] = null;
holes++;
if(logMINOR) Logger.minor(this, "Found (exact)");
return true;
@@ -176,8 +184,9 @@
int nidx = idx;
while(true) {
if(times[nidx] != time) break;
- if(keys[nidx] == key) {
+ if(keys[nidx] == key && clients[nidx] == client) {
keys[nidx] = null;
+ clients[nidx] = null;
holes++;
if(logMINOR) Logger.minor(this, "Found
(backwards)");
return true;
@@ -190,8 +199,9 @@
// Now try forwards
while(true) {
if(times[nidx] != time) break;
- if(keys[nidx] == key) {
+ if(keys[nidx] == key && clients[nidx] == client) {
keys[nidx] = null;
+ clients[nidx] = null;
holes++;
if(logMINOR) Logger.minor(this, "Found
(forwards)");
return true;
@@ -218,6 +228,7 @@
// FIXME reuse the old buffers if it fits
Key[] newKeys = new Key[newSize];
long[] newTimes = new long[newSize];
+ SendableGet[] newClients = new SendableGet[newSize];
// Reset startPtr to 0, and remove holes.
int x = 0;
long lastTime = -1;
@@ -226,6 +237,7 @@
if(keys[i] == null) continue;
newKeys[x] = keys[i];
newTimes[x] = times[i];
+ newClients[x] = clients[i];
if(lastTime > times[i])
Logger.error(this,
"RequestCooldownQueue INCONSISTENCY: times["+i+"] = times[i] but
lastTime="+lastTime);
lastTime = times[i];
@@ -236,6 +248,7 @@
if(keys[i] == null) continue;
newKeys[x] = keys[i];
newTimes[x] = times[i];
+ newClients[x] = clients[i];
if(lastTime > times[i])
Logger.error(this,
"RequestCooldownQueue INCONSISTENCY: times["+i+"] = times[i] but
lastTime="+lastTime);
lastTime = times[i];
@@ -245,6 +258,7 @@
if(keys[i] == null) continue;
newKeys[x] = keys[i];
newTimes[x] = times[i];
+ newClients[x] = clients[i];
if(lastTime > times[i])
Logger.error(this,
"RequestCooldownQueue INCONSISTENCY: times["+i+"] = times[i] but
lastTime="+lastTime);
lastTime = times[i];
@@ -258,6 +272,7 @@
startPtr = 0;
keys = newKeys;
times = newTimes;
+ clients = newClients;
endPtr = x;
}
Modified: trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
2008-04-02 01:08:37 UTC (rev 18904)
+++ trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
2008-04-02 01:29:15 UTC (rev 18905)
@@ -394,7 +394,9 @@
if(dataCooldownTimes[blockNo] > now)
Logger.error(this, "Already on
the cooldown queue! for "+this+" data block no "+blockNo, new
Exception("error"));
else
- dataCooldownTimes[blockNo] =
sched.queueCooldown(key);
+ // FIXME ideally we'd only register
once, with the new segment, but the cost is
+ // trivial, and it simplifies locking.
Reconsider sometime...
+ dataCooldownTimes[blockNo] =
sched.queueCooldown(key, seg);
cooldown = true;
}
} else {
@@ -407,7 +409,7 @@
if(checkCooldownTimes[checkNo] > now)
Logger.error(this, "Already on
the cooldown queue! for "+this+" check block no "+blockNo, new
Exception("error"));
else
- checkCooldownTimes[checkNo] =
sched.queueCooldown(key);
+ checkCooldownTimes[checkNo] =
sched.queueCooldown(key, seg);
cooldown = true;
}
}
Modified: trunk/freenet/src/freenet/node/RequestScheduler.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestScheduler.java 2008-04-02
01:08:37 UTC (rev 18904)
+++ trunk/freenet/src/freenet/node/RequestScheduler.java 2008-04-02
01:29:15 UTC (rev 18905)
@@ -25,7 +25,7 @@
* @param key The key to be added.
* @return The time at which the key will leave the cooldown queue.
*/
- public long queueCooldown(ClientKey key);
+ public long queueCooldown(ClientKey key, SendableGet getter);
/**
* Remove keys from the cooldown queue who have now served their time
and can be requested