Author: toad
Date: 2008-11-14 15:37:44 +0000 (Fri, 14 Nov 2008)
New Revision: 23580
Added:
trunk/freenet/src/freenet/node/BlockedTooLongException.java
Modified:
trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
trunk/freenet/src/freenet/node/FNPPacketMangler.java
trunk/freenet/src/freenet/node/KeyTracker.java
trunk/freenet/src/freenet/node/OutgoingPacketMangler.java
trunk/freenet/src/freenet/node/PacketSender.java
trunk/freenet/src/freenet/node/PeerNode.java
trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java
Log:
Don't try to send packets when we know it will block (throw
WouldBlockException).
Don't busy loop waiting for that to clear either.
After we have been unable to allocate a packet number for 10 minutes,
disconnect, log an error, and tell the user via a useralert.
Modified: trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
===================================================================
--- trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2008-11-14
15:12:16 UTC (rev 23579)
+++ trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2008-11-14
15:37:44 UTC (rev 23580)
@@ -474,6 +474,8 @@
FileOffer.succeededReceiveShort=Successfully received ${filename} from ${node}.
FNPPacketMangler.somePeersDisconnectedStillNotAcked=Probably a bug: please
report: ${count} peers forcibly disconnected due to not acknowledging packets.
FNPPacketMangler.somePeersDisconnectedStillNotAckedDetail=${count} of your
peers are having severe problems (not acknowledging packets even after 10
minutes). This is probably due to a bug in the code. Please report it to us at
the bug tracker at ${link}https://bugs.freenetproject.org/${/link} or at [EMAIL
PROTECTED] Please include this message and what version of the node you are
running. The affected peers (you may not want to include this in your bug
report if they are darknet peers) are:
+PacketSender.somePeersDisconnectedStillNotAcked=Probably a bug: please report:
${count} peers forcibly disconnected due to blocking for a packet number for
over 10 minutes.
+PacketSender.somePeersDisconnectedStillNotAckedDetail=${count} of your peers
are having severe problems (failing to allocate a packet number after 10
minutes). This is probably due to a bug in the code. Please report it to us at
the bug tracker at ${link}https://bugs.freenetproject.org/${/link} or at [EMAIL
PROTECTED] Please include this message and what version of the node you are
running. The affected peers (you may not want to include this in your bug
report if they are darknet peers) are:
GIFFilter.invalidHeader=The file does not contain a valid GIF header.
GIFFilter.invalidHeaderTitle=Invalid header
GIFFilter.notGif=The file you tried to fetch is not a GIF. It might be some
other file format, and your browser may do something dangerous with it,
therefore we have blocked it.
Added: trunk/freenet/src/freenet/node/BlockedTooLongException.java
===================================================================
--- trunk/freenet/src/freenet/node/BlockedTooLongException.java
(rev 0)
+++ trunk/freenet/src/freenet/node/BlockedTooLongException.java 2008-11-14
15:37:44 UTC (rev 23580)
@@ -0,0 +1,13 @@
+package freenet.node;
+
+public class BlockedTooLongException extends Exception {
+
+ public final KeyTracker tracker;
+ public final long delta;
+
+ public BlockedTooLongException(KeyTracker tracker, long delta) {
+ this.tracker = tracker;
+ this.delta = delta;
+ }
+
+}
Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2008-11-14
15:12:16 UTC (rev 23579)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2008-11-14
15:37:44 UTC (rev 23580)
@@ -2014,7 +2014,7 @@
/* (non-Javadoc)
* @see
freenet.node.OutgoingPacketMangler#processOutgoingOrRequeue(freenet.node.MessageItem[],
freenet.node.PeerNode, boolean, boolean)
*/
- public boolean processOutgoingOrRequeue(MessageItem[] messages,
PeerNode pn, boolean neverWaitForPacketNumber, boolean dontRequeue, boolean
onePacket) {
+ public boolean processOutgoingOrRequeue(MessageItem[] messages,
PeerNode pn, boolean neverWaitForPacketNumber, boolean dontRequeue, boolean
onePacket) throws BlockedTooLongException {
String requeueLogString = "";
if(!dontRequeue) {
requeueLogString = ", requeueing";
@@ -2027,6 +2027,10 @@
Logger.error(this, "Not connected while sending
packets: "+pn);
return false;
}
+ if(kt.wouldBlock(false)) {
+ if(logMINOR) Logger.minor(this, "Would block: "+kt);
+ return false;
+ }
int length = 1;
length += kt.countAcks() + kt.countAckRequests() +
kt.countResendRequests();
int callbacksCount = 0;
Modified: trunk/freenet/src/freenet/node/KeyTracker.java
===================================================================
--- trunk/freenet/src/freenet/node/KeyTracker.java 2008-11-14 15:12:16 UTC
(rev 23579)
+++ trunk/freenet/src/freenet/node/KeyTracker.java 2008-11-14 15:37:44 UTC
(rev 23580)
@@ -541,6 +541,11 @@
}
if(cbCount > 0 && logMINOR)
Logger.minor(this, "Executed " + cbCount + "
callbacks");
+ try {
+ wouldBlock(true);
+ } catch (BlockedTooLongException e) {
+ // Ignore, will come up again. In any case it's rather
unlikely...
+ }
}
/**
@@ -570,6 +575,11 @@
throttle.notifyOfPacketAcknowledged();
throttle.setRoundTripTime(System.currentTimeMillis() - timeAdded);
}
+ try {
+ wouldBlock(true);
+ } catch (BlockedTooLongException e) {
+ // Ignore, will come up again. In any case it's rather
unlikely...
+ }
if(callbacks != null) {
for(int i = 0; i < callbacks.length; i++)
callbacks[i].acknowledged();
@@ -711,6 +721,36 @@
}
}
}
+
+ private long timeWouldBlock = -1;
+
+ static final long MAX_WOULD_BLOCK_DELTA = 10*60*1000;
+
+ public boolean wouldBlock(boolean wakeTicker) throws
BlockedTooLongException {
+ long now = System.currentTimeMillis();
+ synchronized(this) {
+ if(sentPacketsContents.wouldBlock(nextPacketNumber)) {
+ if(timeWouldBlock == -1)
+ timeWouldBlock = now;
+ else {
+ long delta = now - timeWouldBlock;
+ if(delta > MAX_WOULD_BLOCK_DELTA) {
+ Logger.error(this, "Not been
able to allocate a packet to tracker "+this+" for "+TimeUtil.formatTime(delta));
+ throw new
BlockedTooLongException(this, delta);
+ }
+ }
+ return true;
+ } else {
+ long delta = now - timeWouldBlock;
+ timeWouldBlock = -1;
+ if(timeWouldBlock != -1 && (delta >
PacketSender.MAX_COALESCING_DELAY)) {
+ Logger.error(this, "Waking
PacketSender: have been blocking for packet ack for
"+TimeUtil.formatTime(delta));
+ } else return false;
+ }
+ }
+ pn.node.ps.wakeUp();
+ return false;
+ }
/**
* @return A packet number for a new outgoing packet.
@@ -727,6 +767,7 @@
if(isDeprecated)
throw new KeyChangedException();
sentPacketsContents.lockNeverBlock(packetNumber);
+ timeWouldBlock = -1;
nextPacketNumber = packetNumber + 1;
if(logMINOR)
Logger.minor(this, "Allocated " + packetNumber
+ " in allocateOutgoingPacketNumberNeverBlock for " + this);
Modified: trunk/freenet/src/freenet/node/OutgoingPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/OutgoingPacketMangler.java 2008-11-14
15:12:16 UTC (rev 23579)
+++ trunk/freenet/src/freenet/node/OutgoingPacketMangler.java 2008-11-14
15:37:44 UTC (rev 23580)
@@ -27,9 +27,10 @@
* @param onePacketOnly If true, we will only send one packet, and will
requeue any
* messages that don't fit in that single packet.
* @return True if we sent a packet.
+ * @throws BlockedTooLongException
*/
public boolean processOutgoingOrRequeue(MessageItem[] messages,
PeerNode pn,
- boolean neverWaitForPacketNumber, boolean dontRequeue,
boolean onePacketOnly);
+ boolean neverWaitForPacketNumber, boolean dontRequeue,
boolean onePacketOnly) throws BlockedTooLongException;
/**
* Resend a single packet.
Modified: trunk/freenet/src/freenet/node/PacketSender.java
===================================================================
--- trunk/freenet/src/freenet/node/PacketSender.java 2008-11-14 15:12:16 UTC
(rev 23579)
+++ trunk/freenet/src/freenet/node/PacketSender.java 2008-11-14 15:37:44 UTC
(rev 23580)
@@ -4,15 +4,21 @@
package freenet.node;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.TreeMap;
import java.util.Vector;
import org.tanukisoftware.wrapper.WrapperManager;
+import freenet.io.comm.Peer;
+import freenet.l10n.L10n;
+import freenet.node.useralerts.UserAlert;
import freenet.support.FileLoggerHook;
+import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.OOMHandler;
+import freenet.support.TimeUtil;
import freenet.support.io.NativeThread;
/**
@@ -251,6 +257,7 @@
continue;
}
+ try {
if(pn.maybeSendPacket(now, rpiTemp, rpiIntTemp)
&& canSendThrottled) {
canSendThrottled = false;
count = node.outputThrottle.getCount();
@@ -265,6 +272,11 @@
newBrokeAt = i;
}
}
+ } catch (BlockedTooLongException e) {
+ Logger.error(this, "Waited too long:
"+TimeUtil.formatTime(e.delta)+" to allocate a packet number to send to
"+this+" on "+e.tracker+" - DISCONNECTING!");
+ pn.forceDisconnect(true);
+ onForceDisconnectBlockTooLong(pn, e);
+ }
long urgentTime = pn.getNextUrgentTime(now);
// Should spam the logs, unless there is a
deadlock
@@ -409,6 +421,107 @@
return brokeAt;
}
+ private HashSet<Peer> peersDumpedBlockedTooLong = new HashSet<Peer>();
+
+ private void onForceDisconnectBlockTooLong(PeerNode pn,
BlockedTooLongException e) {
+ Peer p = pn.getPeer();
+ synchronized(peersDumpedBlockedTooLong) {
+ peersDumpedBlockedTooLong.add(p);
+ if(peersDumpedBlockedTooLong.size() > 1) return;
+ }
+ node.clientCore.alerts.register(peersDumpedBlockedTooLongAlert);
+ }
+
+ private UserAlert peersDumpedBlockedTooLongAlert = new UserAlert() {
+
+ public String anchor() {
+ return "disconnectedStillNotAcked";
+ }
+
+ public String dismissButtonText() {
+ return null;
+ }
+
+ public short getPriorityClass() {
+ return UserAlert.ERROR;
+ }
+
+ public String getShortText() {
+ int sz;
+ synchronized(peersDumpedBlockedTooLong) {
+ sz = peersDumpedBlockedTooLong.size();
+ }
+ return l10n("somePeersDisconnectedBlockedTooLong",
"count", Integer.toString(sz));
+ }
+
+ public HTMLNode getHTMLText() {
+ HTMLNode div = new HTMLNode("div");
+ Peer[] peers;
+ synchronized(peersDumpedBlockedTooLong) {
+ peers = peersDumpedBlockedTooLong.toArray(new
Peer[peersDumpedBlockedTooLong.size()]);
+ }
+ L10n.addL10nSubstitution(div,
"FNPPacketMangler.somePeersDisconnectedBlockedTooLongDetail",
+ new String[] { "count", "link", "/link"
}
+ , new String[] {
Integer.toString(peers.length), "<a
href=\"/?_CHECKED_HTTP_=https://bugs.freenetproject.org/\">", "</a>" });
+ HTMLNode list = div.addChild("ul");
+ for(Peer peer : peers) {
+ list.addChild("li", peer.toString());
+ }
+ return div;
+ }
+
+ public String getText() {
+ StringBuffer sb = new StringBuffer();
+ Peer[] peers;
+ synchronized(peersDumpedBlockedTooLong) {
+ peers = peersDumpedBlockedTooLong.toArray(new
Peer[peersDumpedBlockedTooLong.size()]);
+ }
+
sb.append(l10n("somePeersDisconnectedStillNotAckedDetail",
+ new String[] { "count", "link", "/link"
},
+ new String[] {
Integer.toString(peers.length), "", "" } ));
+ sb.append('\n');
+ for(Peer peer : peers) {
+ sb.append('\t');
+ sb.append(peer.toString());
+ sb.append('\n');
+ }
+ return sb.toString();
+ }
+
+ public String getTitle() {
+ return getShortText();
+ }
+
+ public Object getUserIdentifier() {
+ return PacketSender.this;
+ }
+
+ public boolean isEventNotification() {
+ return false;
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+
+ public void isValid(boolean validity) {
+ // Ignore
+ }
+
+ public void onDismiss() {
+ // Ignore
+ }
+
+ public boolean shouldUnregisterOnDismiss() {
+ return false;
+ }
+
+ public boolean userCanDismiss() {
+ return false;
+ }
+
+ };
+
/** Wake up, and send any queued packets. */
void wakeUp() {
// Wake up if needed
@@ -417,12 +530,18 @@
}
}
+ protected String l10n(String key, String[] patterns, String[] values) {
+ return L10n.getString("PacketSender."+key, patterns, values);
+ }
+
+ protected String l10n(String key, String pattern, String value) {
+ return L10n.getString("PacketSender."+key, pattern, value);
+ }
+
public void queueTimedJob(Runnable job, long offset) {
queueTimedJob(job, "Scheduled job: "+job, offset, false);
}
-
-
public void queueTimedJob(Runnable runner, String name, long offset,
boolean runOnTickerAnyway) {
// Run directly *if* that won't cause any priority problems.
if(offset <= 0 && !runOnTickerAnyway) {
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2008-11-14 15:12:16 UTC
(rev 23579)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2008-11-14 15:37:44 UTC
(rev 23580)
@@ -1256,23 +1256,35 @@
*/
public long getNextUrgentTime(long now) {
long t = Long.MAX_VALUE;
+ KeyTracker cur;
+ KeyTracker prev;
synchronized(this) {
- KeyTracker kt = currentTracker;
- if(kt != null) {
+ cur = currentTracker;
+ prev = previousTracker;
+ }
+ KeyTracker kt = cur;
+ try {
+ if(kt != null && !kt.wouldBlock(false)) {
long next = kt.getNextUrgentTime();
t = Math.min(t, next);
if(next < now && logMINOR)
Logger.minor(this, "Next urgent time from
curTracker less than now");
if(kt.hasPacketsToResend()) return now;
}
- kt = previousTracker;
- if(kt != null) {
+ } catch (BlockedTooLongException e) {
+ // Ignore for now, it will come back around
+ }
+ kt = prev;
+ try {
+ if(kt != null && !kt.wouldBlock(false)) {
long next = kt.getNextUrgentTime();
t = Math.min(t, next);
if(next < now && logMINOR)
Logger.minor(this, "Next urgent time from
prevTracker less than now");
if(kt.hasPacketsToResend()) return now;
}
+ } catch (BlockedTooLongException e) {
+ // Ignore for now, it will come back around
}
t = messageQueue.getNextUrgentTime(t, now);
return t;
@@ -4016,8 +4028,9 @@
* @param now
* @param rpiTemp
* @param rpiTemp
+ * @throws BlockedTooLongException
*/
- public boolean maybeSendPacket(long now, Vector<ResendPacketItem>
rpiTemp, int[] rpiIntTemp) {
+ public boolean maybeSendPacket(long now, Vector<ResendPacketItem>
rpiTemp, int[] rpiIntTemp) throws BlockedTooLongException {
// If there are any urgent notifications, we must send a packet.
boolean mustSend = false;
boolean mustSendPacket = false;
Modified: trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java
===================================================================
--- trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java
2008-11-14 15:12:16 UTC (rev 23579)
+++ trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java
2008-11-14 15:37:44 UTC (rev 23580)
@@ -146,6 +146,11 @@
}
}
+ public boolean wouldBlock(int index) {
+ if(minValue == -1) return false;
+ return (index - minValue >= maxRange);
+ }
+
/**
* Wait until add(index, whatever) would return true.
* If this returns, add(index, whatever) will work.
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs