[freenet-cvs] r18905 - in trunk/freenet/src/freenet: client/async node

toad at freenetproject.org toad at freenetproject.org
Wed Apr 2 01:29:16 UTC 2008


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 




More information about the cvs mailing list