2005-10-29 jrandom
* Improved the bandwidth throtting on tunnel participation, especially for low bandwidth peers. * Improved failure handling in SSU with proactive reestablishment of failing idle peers, and rather than shitlisting a peer who failed too much, drop the SSU session and allow a new attempt (which, if it fails, will cause a shitlisting) * Clarify the cause of the shitlist on the profiles page, and include bandwidth limiter info at the bottom of the peers page.
This commit is contained in:
@ -29,6 +29,7 @@ public class PeerHelper {
|
||||
public String getPeerSummary() {
|
||||
try {
|
||||
_context.commSystem().renderStatusHTML(_out);
|
||||
_context.bandwidthLimiter().renderStatusHTML(_out);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
12
history.txt
12
history.txt
@ -1,4 +1,14 @@
|
||||
$Id: history.txt,v 1.306 2005/10/25 14:13:54 jrandom Exp $
|
||||
$Id: history.txt,v 1.307 2005/10/28 17:26:55 jrandom Exp $
|
||||
|
||||
2005-10-29 jrandom
|
||||
* Improved the bandwidth throtting on tunnel participation, especially for
|
||||
low bandwidth peers.
|
||||
* Improved failure handling in SSU with proactive reestablishment of
|
||||
failing idle peers, and rather than shitlisting a peer who failed too
|
||||
much, drop the SSU session and allow a new attempt (which, if it fails,
|
||||
will cause a shitlisting)
|
||||
* Clarify the cause of the shitlist on the profiles page, and include
|
||||
bandwidth limiter info at the bottom of the peers page.
|
||||
|
||||
2005-10-26 jrandom
|
||||
* In Syndie, propogate the subject and tags in a reply, and show the parent
|
||||
|
@ -26,7 +26,7 @@ tunnel.1.i2cpPort=7654
|
||||
tunnel.1.option.inbound.nickname=shared clients
|
||||
tunnel.1.option.outbound.nickname=shared clients
|
||||
tunnel.1.option.i2p.streaming.connectDelay=1000
|
||||
tunnel.1.option.i2p.maxWindowSize=1
|
||||
tunnel.1.option.i2p.streaming.maxWindowSize=1
|
||||
tunnel.1.startOnLoad=true
|
||||
|
||||
# I2P's cvs server
|
||||
|
@ -50,6 +50,8 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
_context.statManager().createRateStat("router.throttleTunnelProbTooFast", "How many tunnels beyond the previous 1h average are we participating in when we throttle?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelProbTestSlow", "How slow are our tunnel tests when our average exceeds the old average and we throttle?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelBandwidthExceeded", "How much bandwidth is allocated when we refuse due to bandwidth allocation?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelBytesAllowed", "How many bytes are allowed to be sent when we get a tunnel request (period is how many are currently allocated)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelBytesUsed", "Used Bps at request (period = max KBps)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
}
|
||||
|
||||
public boolean acceptNetworkMessage() {
|
||||
@ -212,7 +214,13 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
r = null;
|
||||
if (rs != null)
|
||||
r = rs.getRate(10*60*1000);
|
||||
double bytesAllocated = (r != null ? r.getCurrentTotalValue() * 1024 : 0);
|
||||
double messagesPerTunnel = (r != null ? r.getAverageValue() : 0d);
|
||||
if (messagesPerTunnel < DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE)
|
||||
messagesPerTunnel = DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE;
|
||||
int participatingTunnels = (r != null ? (int) (r.getLastEventCount() + r.getCurrentEventCount()) : 0);
|
||||
if (participatingTunnels <= 0)
|
||||
participatingTunnels = _context.tunnelManager().getParticipatingCount();
|
||||
double bytesAllocated = messagesPerTunnel * participatingTunnels * 1024;
|
||||
|
||||
if (!allowTunnel(bytesAllocated, numTunnels)) {
|
||||
_context.statManager().addRateData("router.throttleTunnelBandwidthExceeded", (long)bytesAllocated, 0);
|
||||
@ -227,6 +235,8 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
return TUNNEL_ACCEPT;
|
||||
}
|
||||
|
||||
private static final int DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE = 600; // 1KBps
|
||||
|
||||
/**
|
||||
* with bytesAllocated already accounted for across the numTunnels existing
|
||||
* tunnels we have agreed to, can we handle another tunnel with our existing
|
||||
@ -234,26 +244,33 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
*
|
||||
*/
|
||||
private boolean allowTunnel(double bytesAllocated, int numTunnels) {
|
||||
long bytesAllowed = getBytesAllowed();
|
||||
|
||||
bytesAllowed *= getSharePercentage();
|
||||
|
||||
double bytesPerTunnel = (numTunnels > 0 ? bytesAllocated / numTunnels : 0);
|
||||
double toAllocate = (numTunnels > 0 ? bytesPerTunnel * (numTunnels + 1) : 0);
|
||||
|
||||
double pctFull = toAllocate / bytesAllowed;
|
||||
int maxKBps = Math.min(_context.bandwidthLimiter().getOutboundKBytesPerSecond(), _context.bandwidthLimiter().getInboundKBytesPerSecond());
|
||||
int used = (int)Math.max(_context.bandwidthLimiter().getSendBps(), _context.bandwidthLimiter().getReceiveBps());
|
||||
int availBps = (int)(((maxKBps*1024) - used) * getSharePercentage());
|
||||
|
||||
_context.statManager().addRateData("router.throttleTunnelBytesUsed", used, maxKBps);
|
||||
_context.statManager().addRateData("router.throttleTunnelBytesAllowed", availBps, (long)bytesAllocated);
|
||||
|
||||
if (maxKBps <= 8) {
|
||||
// lets be more conservative for dialup users and assume 1KBps per tunnel
|
||||
return ( (numTunnels + 1)*1024 < availBps);
|
||||
}
|
||||
|
||||
double growthFactor = ((double)(numTunnels+1))/(double)numTunnels;
|
||||
double toAllocate = (numTunnels > 0 ? bytesAllocated * growthFactor : 0);
|
||||
|
||||
double allocatedKBps = toAllocate / (10 * 60 * 1024);
|
||||
double pctFull = allocatedKBps / availBps;
|
||||
|
||||
if (pctFull < 1.0) { // (_context.random().nextInt(100) > 100 * pctFull) {
|
||||
if ( (pctFull < 1.0) && (pctFull >= 0.0) ) { // (_context.random().nextInt(100) > 100 * pctFull) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Probabalistically allowing the tunnel w/ " + pctFull + " of our " + bytesAllowed
|
||||
+ "bytes/" + allocatedKBps + "KBps allocated through " + numTunnels + " tunnels");
|
||||
_log.debug("Probabalistically allowing the tunnel w/ " + pctFull + " of our " + availBps
|
||||
+ "Bps/" + allocatedKBps + "KBps allocated through " + numTunnels + " tunnels");
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Rejecting the tunnel w/ " + pctFull + " of our " + bytesAllowed
|
||||
+ "bytes allowed (" + toAllocate + "bytes / " + allocatedKBps
|
||||
_log.debug("Rejecting the tunnel w/ " + pctFull + " of our " + availBps
|
||||
+ "Bps allowed (" + toAllocate + "bytes / " + allocatedKBps
|
||||
+ "KBps) through " + numTunnels + " tunnels");
|
||||
return false;
|
||||
}
|
||||
@ -268,7 +285,11 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
String pct = _context.getProperty(PROP_BANDWIDTH_SHARE_PERCENTAGE, "0.8");
|
||||
if (pct != null) {
|
||||
try {
|
||||
return Double.parseDouble(pct);
|
||||
double d = Double.parseDouble(pct);
|
||||
if (d > 1)
|
||||
return d/100d; // *cough* sometimes its 80 instead of .8 (!stab jrandom)
|
||||
else
|
||||
return d;
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unable to get the share percentage");
|
||||
@ -276,50 +297,7 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
}
|
||||
return 0.8;
|
||||
}
|
||||
|
||||
/**
|
||||
* BytesPerSecond that we can pass along data
|
||||
*/
|
||||
private long getBytesAllowed() {
|
||||
String kbpsOutStr = _context.getProperty("i2np.bandwidth.outboundKBytesPerSecond");
|
||||
long kbpsOut = -1;
|
||||
if (kbpsOutStr != null) {
|
||||
try {
|
||||
kbpsOut = Integer.parseInt(kbpsOutStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unable to get the bytes allowed (outbound)");
|
||||
}
|
||||
}
|
||||
|
||||
String kbpsInStr = _context.getProperty("i2np.bandwidth.inboundKBytesPerSecond");
|
||||
long kbpsIn = -1;
|
||||
if (kbpsInStr != null) {
|
||||
try {
|
||||
kbpsIn = Integer.parseInt(kbpsInStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Unable to get the bytes allowed (inbound)");
|
||||
}
|
||||
}
|
||||
|
||||
// whats our choke?
|
||||
long kbps = (kbpsOut > kbpsIn ? kbpsIn : kbpsOut);
|
||||
|
||||
if (kbps <= 0) {
|
||||
try {
|
||||
kbps = Integer.parseInt(_context.getProperty(PROP_DEFAULT_KBPS_THROTTLE, "64")); // absurd
|
||||
} catch (NumberFormatException nfe) {
|
||||
kbps = 64;
|
||||
}
|
||||
}
|
||||
|
||||
return kbps
|
||||
* 60 // per minute
|
||||
* 10 // per 10 minute period
|
||||
* 1024; // bytes;
|
||||
}
|
||||
|
||||
|
||||
/** dont ever probabalistically throttle tunnels if we have less than this many */
|
||||
private int getMinThrottleTunnels() {
|
||||
try {
|
||||
|
@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
public final static String ID = "$Revision: 1.277 $ $Date: 2005/10/25 14:13:53 $";
|
||||
public final static String ID = "$Revision: 1.278 $ $Date: 2005/10/28 17:26:53 $";
|
||||
public final static String VERSION = "0.6.1.3";
|
||||
public final static long BUILD = 8;
|
||||
public final static long BUILD = 9;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
System.out.println("Router ID: " + RouterVersion.ID);
|
||||
|
@ -75,7 +75,7 @@ public class Shitlist {
|
||||
Date oldDate = (Date)_shitlist.put(peer, new Date(_context.clock().now() + period));
|
||||
wasAlready = (null == oldDate);
|
||||
if (reason != null) {
|
||||
if (!wasAlready)
|
||||
if (!wasAlready || (!_shitlistCause.containsKey(peer)) )
|
||||
_shitlistCause.put(peer, reason);
|
||||
} else {
|
||||
_shitlistCause.remove(peer);
|
||||
|
@ -100,6 +100,9 @@ public class FIFOBandwidthLimiter {
|
||||
public float getSendBps() { return _sendBps; }
|
||||
public float getReceiveBps() { return _recvBps; }
|
||||
|
||||
public int getOutboundKBytesPerSecond() { return _refiller.getOutboundKBytesPerSecond(); }
|
||||
public int getInboundKBytesPerSecond() { return _refiller.getInboundKBytesPerSecond(); }
|
||||
|
||||
public void reinitialize() {
|
||||
_pendingInboundRequests.clear();
|
||||
_pendingOutboundRequests.clear();
|
||||
|
@ -328,4 +328,7 @@ class FIFOBandwidthRefiller implements Runnable {
|
||||
_limiter.setOutboundBurstBytes(DEFAULT_BURST_SECONDS * _outboundBurstKBytesPerSecond * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
int getOutboundKBytesPerSecond() { return _outboundKBytesPerSecond; }
|
||||
int getInboundKBytesPerSecond() { return _inboundKBytesPerSecond; }
|
||||
}
|
@ -65,6 +65,8 @@ public class PeerState {
|
||||
private long _currentReceiveSecond;
|
||||
/** when did we last send them a packet? */
|
||||
private long _lastSendTime;
|
||||
/** when did we last send them a message that was ACKed */
|
||||
private long _lastSendFullyTime;
|
||||
/** when did we last receive a packet from them? */
|
||||
private long _lastReceiveTime;
|
||||
/** how many consecutive messages have we sent and not received an ACK to */
|
||||
@ -270,6 +272,8 @@ public class PeerState {
|
||||
public long getCurrentReceiveSecond() { return _currentReceiveSecond; }
|
||||
/** when did we last send them a packet? */
|
||||
public long getLastSendTime() { return _lastSendTime; }
|
||||
/** when did we last send them a message that was ACKed? */
|
||||
public long getLastSendFullyTime() { return _lastSendFullyTime; }
|
||||
/** when did we last receive a packet from them? */
|
||||
public long getLastReceiveTime() { return _lastReceiveTime; }
|
||||
/** how many seconds have we sent packets without any ACKs received? */
|
||||
@ -658,6 +662,7 @@ public class PeerState {
|
||||
if (_sendWindowBytes > MAX_SEND_WINDOW_BYTES)
|
||||
_sendWindowBytes = MAX_SEND_WINDOW_BYTES;
|
||||
_lastReceiveTime = _context.clock().now();
|
||||
_lastSendFullyTime = _lastReceiveTime;
|
||||
|
||||
if (true) {
|
||||
if (_sendWindowBytesRemaining + bytesACKed <= _sendWindowBytes)
|
||||
|
@ -147,6 +147,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_context.statManager().createRateStat("udp.statusUnknown", "How many times the peer test returned an unknown result", "udp", new long[] { 5*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.addressTestInsteadOfUpdate", "How many times we fire off a peer test of ourselves instead of adjusting our own reachable address?", "udp", new long[] { 1*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.addressUpdated", "How many times we adjust our own reachable IP address", "udp", new long[] { 1*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.proactiveReestablish", "How long a session was idle for when we proactively reestablished it", "udp", new long[] { 1*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
@ -661,6 +662,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return (pref != null) && "true".equals(pref);
|
||||
}
|
||||
|
||||
private static final int MAX_IDLE_TIME = 60*1000;
|
||||
|
||||
public String getStyle() { return STYLE; }
|
||||
public void send(OutNetMessage msg) {
|
||||
if (msg == null) return;
|
||||
@ -668,13 +671,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (msg.getTarget().getIdentity() == null) return;
|
||||
|
||||
Hash to = msg.getTarget().getIdentity().calculateHash();
|
||||
if (getPeerState(to) != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending outbound message to an established peer: " + to.toBase64());
|
||||
PeerState peer = getPeerState(to);
|
||||
if (peer != null) {
|
||||
long lastSend = peer.getLastSendFullyTime();
|
||||
long lastRecv = peer.getLastReceiveTime();
|
||||
long now = _context.clock().now();
|
||||
if ( (lastSend > 0) && (lastRecv > 0) ) {
|
||||
if ( (now - lastSend > MAX_IDLE_TIME) &&
|
||||
(now - lastRecv > MAX_IDLE_TIME) &&
|
||||
(peer.getConsecutiveFailedSends() > 0) ) {
|
||||
// peer is waaaay idle, drop the con and queue it up as a new con
|
||||
dropPeer(peer, false);
|
||||
_establisher.establish(msg);
|
||||
_context.statManager().addRateData("udp.proactiveReestablish", now-lastSend, now-peer.getKeyEstablishedTime());
|
||||
return;
|
||||
}
|
||||
}
|
||||
_outboundMessages.add(msg);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending outbound message to an unestablished peer: " + to.toBase64());
|
||||
_establisher.establish(msg);
|
||||
}
|
||||
}
|
||||
@ -836,7 +850,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Consecutive failure #" + consecutive + " sending to " + msg.getPeer());
|
||||
if (consecutive > MAX_CONSECUTIVE_FAILED)
|
||||
dropPeer(msg.getPeer());
|
||||
dropPeer(msg.getPeer(), false);
|
||||
}
|
||||
failed(msg.getMessage());
|
||||
}
|
||||
|
Reference in New Issue
Block a user