Compare commits

...

9 Commits

Author SHA1 Message Date
jrandom
230d4cd23f * 2006-04-13 0.6.1.15 released 2006-04-13 12:40:21 +00:00
jrandom
e9b6fcc0a4 2006-04-12 jrandom
* Added a further failsafe against trying to queue up too many messages to
      a peer.
2006-04-13 04:22:06 +00:00
jrandom
8fcb871409 2006-04-12 jrandom
* Watch out for failed syndie index fetches (thanks bar!)
2006-04-12 06:49:01 +00:00
jrandom
83bef43fd5 2006-04-11 jrandom
* Throttling improvements on SSU - throttle all transmissions to a peer
      when we are retransmitting, not just retransmissions.  Also, if
      we're already retransmitting to a peer, probabalistically tail drop new
      messages targetting that peer, based on the estimated wait time before
      transmission.
    * Fixed the rounding error in the inbound tunnel drop probability.
2006-04-11 13:39:06 +00:00
jrandom
b4fc6ca31b 2006-04-10 jrandom
* Include a combined send/receive graph (good idea cervantes!)
    * Proactively drop inbound tunnel requests probabalistically as the
      estimated queue time approaches our limit, rather than letting them all
      through up to that limit.
2006-04-10 05:37:28 +00:00
jrandom
ab3f1b708d 2006-04-08 jrandom
* Stat summarization fix (removing the occational holes in the jrobin
      graphs)
2006-04-09 01:14:08 +00:00
jrandom
c76402a160 2006-04-08 jrandom
* Process inbound tunnel requests more efficiently
    * Proactively drop inbound tunnel requests if the queue before we'd
      process it in is too long (dynamically adjusted by cpu load)
    * Adjust the tunnel rejection throttle to reject requeusts when we have to
      proactively drop too many requests.
    * Display the number of pending inbound tunnel join requests on the router
      console (as the "handle backlog")
    * Include a few more stats in the default set of graphs
2006-04-08 06:15:43 +00:00
jrandom
a50c73aa5e 2006-04-06 jrandom
* Fix for a bug in the new irc ping/pong filter (thanks Complication!)
2006-04-07 01:26:32 +00:00
jrandom
5aa66795d2 2006-04-06 jrandom
* Fixed a typo in the reply cleanup code
2006-04-06 10:33:44 +00:00
28 changed files with 401 additions and 105 deletions

View File

@@ -228,36 +228,6 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
String outmsg = outboundFilter(inmsg);
if(outmsg!=null)
{
if (outmsg.indexOf("PING") >= 0) {
// Most clients just send a PING and are happy with any old PONG. Others,
// like BitchX, actually expect certain behavior. It sends two different pings:
// "PING :irc.freshcoffee.i2p" and "PING 1234567890 127.0.0.1" (where the IP is the proxy)
// the PONG to the former seems to be "PONG 127.0.0.1", while the PONG to the later is
// ":irc.freshcoffee.i2p PONG irc.freshcoffe.i2p :1234567890".
// We don't want to send them our proxy's IP address, so we need to rewrite the PING
// sent to the server, but when we get a PONG back, use what we expected, rather than
// what they sent.
//
// Yuck.
StringTokenizer tok = new StringTokenizer(inmsg, " ");
int tokens = tok.countTokens();
if ( (tokens <= 2) || (tokens == 3) ) { // "PING nonce" or "PING nonce serverIP"
tok.nextToken(); // skip
//_expectedPong = "PONG 127.0.0.1 :" + tok.nextToken();
_expectedPong = "PONG " + tok.nextToken();
} else {
// if it isn't one of those two, we will filter out all PONGs, which means
// the client will fail. whee!
if (_log.shouldLog(Log.ERROR))
_log.error("IRC client sent a PING we don't understand (\"" + inmsg + "\"), so we're filtering it");
_expectedPong = null;
}
if (_log.shouldLog(Log.WARN)) {
_log.warn("outbound rewritten PING: "+outmsg + ", waiting for [" + _expectedPong + "]");
_log.warn(" - outbound was: "+inmsg);
}
}
if(!inmsg.equals(outmsg)) {
if (_log.shouldLog(Log.WARN)) {
_log.warn("outbound FILTERED: "+outmsg);
@@ -377,7 +347,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
return null;
}
public static String outboundFilter(String s) {
public String outboundFilter(String s) {
String field[]=s.split(" ",3);
String command;
@@ -415,18 +385,38 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
command = field[0].toUpperCase();
if ("PING".equals(command)) {
// e.g. "PING", "PING nonce", or "PING nonce serverIP"
if (field.length == 1) {
return "PING";
} else if (field.length == 2) {
return "PING " + field[1];
} else if (field.length == 3) {
return "PING " + field[1];
// Most clients just send a PING and are happy with any old PONG. Others,
// like BitchX, actually expect certain behavior. It sends two different pings:
// "PING :irc.freshcoffee.i2p" and "PING 1234567890 127.0.0.1" (where the IP is the proxy)
// the PONG to the former seems to be "PONG 127.0.0.1", while the PONG to the later is
// ":irc.freshcoffee.i2p PONG irc.freshcoffe.i2p :1234567890".
// We don't want to send them our proxy's IP address, so we need to rewrite the PING
// sent to the server, but when we get a PONG back, use what we expected, rather than
// what they sent.
//
// Yuck.
String rv = null;
if (field.length == 1) { // PING
rv = "PING";
_expectedPong = "PONG 127.0.0.1";
} else if (field.length == 2) { // PING nonce
rv = "PING " + field[1];
_expectedPong = "PONG " + field[1];
} else if (field.length == 3) { // PING nonce serverLocation
rv = "PING " + field[1];
_expectedPong = "PONG " + field[1];
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
return null;
rv = null;
_expectedPong = null;
}
if (_log.shouldLog(Log.WARN))
_log.warn("sending ping " + rv + ", waiting for " + _expectedPong + " orig was [" + s + "]");
return rv;
}
if ("PONG".equals(command))
return "PONG 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works

View File

@@ -55,6 +55,12 @@ public class GraphHelper {
public String getImages() {
try {
_out.write("<img src=\"viewstat.jsp?stat=bw.combined"
+ "&amp;periodCount=" + _periodCount
+ "&amp;width=" + _width
+ "&amp;height=" + _height
+ "\" title=\"Combined bandwidth graph\" />\n");
List listeners = StatSummarizer.instance().getListeners();
for (int i = 0; i < listeners.size(); i++) {
SummaryListener lsnr = (SummaryListener)listeners.get(i);

View File

@@ -5,18 +5,27 @@ import java.util.*;
import net.i2p.stat.*;
import net.i2p.router.*;
import net.i2p.util.Log;
import java.awt.Color;
import org.jrobin.graph.RrdGraph;
import org.jrobin.graph.RrdGraphDef;
import org.jrobin.graph.RrdGraphDefTemplate;
import org.jrobin.core.RrdException;
/**
*
*/
public class StatSummarizer implements Runnable {
private RouterContext _context;
private Log _log;
/** list of SummaryListener instances */
private List _listeners;
private static StatSummarizer _instance;
public StatSummarizer() {
_context = (RouterContext)RouterContext.listContexts().get(0); // fuck it, only summarize one per jvm
_log = _context.logManager().getLog(getClass());
_listeners = new ArrayList(16);
_instance = this;
}
@@ -45,6 +54,10 @@ public class StatSummarizer implements Runnable {
",router.activePeers.60000" +
",router.activeSendPeers.60000" +
",tunnel.acceptLoad.60000" +
",tunnel.dropLoadProactive.60000" +
",tunnel.buildExploratorySuccess.60000" +
",tunnel.buildExploratoryReject.60000" +
",tunnel.buildExploratoryExpire.60000" +
",client.sendAckTime.60000" +
",client.dispatchNoACK.60000" +
",transport.sendMessageFailureLifetime.60000" +
@@ -124,6 +137,69 @@ public class StatSummarizer implements Runnable {
return false;
}
public boolean renderRatePng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException {
long end = _context.clock().now();
if (periodCount <= 0) periodCount = SummaryListener.PERIODS;
if (periodCount > SummaryListener.PERIODS)
periodCount = SummaryListener.PERIODS;
long period = 60*1000;
long start = end - period*periodCount;
long begin = System.currentTimeMillis();
try {
RrdGraphDef def = new RrdGraphDef();
def.setTimePeriod(start/1000, end/1000);
String title = "Bandwidth usage";
if (!hideTitle)
def.setTitle(title);
String sendName = SummaryListener.createName(_context, "bw.sendRate.60000");
String recvName = SummaryListener.createName(_context, "bw.recvRate.60000");
def.datasource(sendName, sendName, sendName, "AVERAGE", "MEMORY");
def.datasource(recvName, recvName, recvName, "AVERAGE", "MEMORY");
def.area(sendName, Color.BLUE, "Outbound bytes/second");
//def.line(sendName, Color.BLUE, "Outbound bytes/second", 3);
//def.line(recvName, Color.RED, "Inbound bytes/second@r", 3);
def.area(recvName, Color.RED, "Inbound bytes/second@r");
if (!hideLegend) {
def.gprint(sendName, "AVERAGE", "outbound average: @2@sbytes/second");
def.gprint(sendName, "MAX", " max: @2@sbytes/second@r");
def.gprint(recvName, "AVERAGE", "inbound average: @2bytes/second@s");
def.gprint(recvName, "MAX", " max: @2@sbytes/second@r");
}
if (!showCredit)
def.setShowSignature(false);
if (hideLegend)
def.setShowLegend(false);
if (hideGrid) {
def.setGridX(false);
def.setGridY(false);
}
//System.out.println("rendering: path=" + path + " dsNames[0]=" + dsNames[0] + " dsNames[1]=" + dsNames[1] + " lsnr.getName=" + _listener.getName());
def.setAntiAliasing(false);
//System.out.println("Rendering: \n" + def.exportXmlTemplate());
//System.out.println("*****************\nData: \n" + _listener.getData().dump());
RrdGraph graph = new RrdGraph(def);
//System.out.println("Graph created");
byte data[] = null;
if ( (width <= 0) || (height <= 0) )
data = graph.getPNGBytes();
else
data = graph.getPNGBytes(width, height);
long timeToPlot = System.currentTimeMillis() - begin;
out.write(data);
//File t = File.createTempFile("jrobinData", ".xml");
//_listener.getData().dumpXml(new FileOutputStream(t));
//System.out.println("plotted: " + (data != null ? data.length : 0) + " bytes in " + timeToPlot
// ); // + ", data written to " + t.getAbsolutePath());
return true;
} catch (RrdException re) {
_log.error("Error rendering", re);
throw new IOException("Error plotting: " + re.getMessage());
} catch (IOException ioe) {
_log.error("Error rendering", ioe);
throw ioe;
}
}
/**
* @param specs statName.period,statName.period,statName.period
* @return list of Rate objects

View File

@@ -493,6 +493,13 @@ public class SummaryHelper {
return _context.throttle().getTunnelLag() + "ms";
}
public String getInboundBacklog() {
if (_context == null)
return "0";
return String.valueOf(_context.tunnelManager().getInboundBuildQueueSize());
}
public boolean updateAvailable() {
return NewsFetcher.getInstance(_context).updateAvailable();
}

View File

@@ -78,7 +78,7 @@ class SummaryListener implements RateSummaryListener {
* munged version from the user/developer-visible name.
*
*/
private static String createName(I2PAppContext ctx, String wanted) {
static String createName(I2PAppContext ctx, String wanted) {
return ctx.sha().calculateHash(DataHelper.getUTF8(wanted)).toBase64().substring(0,20);
}

View File

@@ -83,6 +83,7 @@
<b>Job lag:</b> <jsp:getProperty name="helper" property="jobLag" /><br />
<b>Message delay:</b> <jsp:getProperty name="helper" property="messageDelay" /><br />
<b>Tunnel lag:</b> <jsp:getProperty name="helper" property="tunnelLag" /><br />
<b>Handle backlog:</b> <jsp:getProperty name="helper" property="inboundBacklog" /><br />
<hr />
</div>

View File

@@ -9,18 +9,25 @@ if (templateFile != null) {
net.i2p.stat.Rate rate = null;
String stat = request.getParameter("stat");
String period = request.getParameter("period");
boolean fakeBw = (stat != null && ("bw.combined".equals(stat)));
net.i2p.stat.RateStat rs = net.i2p.I2PAppContext.getGlobalContext().statManager().getRate(stat);
if ( !rendered && (rs != null)) {
if ( !rendered && ((rs != null) || fakeBw) ) {
long per = -1;
try {
per = Long.parseLong(period);
rate = rs.getRate(per);
if (rate != null) {
if (fakeBw)
per = 60*1000;
else
per = Long.parseLong(period);
if (!fakeBw)
rate = rs.getRate(per);
if ( (rate != null) || (fakeBw) ) {
java.io.OutputStream cout = response.getOutputStream();
String format = request.getParameter("format");
if ("xml".equals(format)) {
response.setContentType("text/xml");
rendered = net.i2p.router.web.StatSummarizer.instance().getXML(rate, cout);
if (!fakeBw) {
response.setContentType("text/xml");
rendered = net.i2p.router.web.StatSummarizer.instance().getXML(rate, cout);
}
} else {
response.setContentType("image/png");
int width = -1;
@@ -39,7 +46,10 @@ if ( !rendered && (rs != null)) {
boolean showCredit = true;
if (request.getParameter("showCredit") != null)
showCredit = Boolean.valueOf(""+request.getParameter("showCredit")).booleanValue();
rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit);
if (fakeBw)
rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit);
else
rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit);
}
if (rendered)
cout.close();

View File

@@ -1066,7 +1066,7 @@ public class BlogManager {
}
public boolean isBanned(Hash blog) {
if (blog == null) return false;
if ( (blog == null) || (blog.getData() == null) || (blog.getData().length <= 0) ) return false;
String str = blog.toBase64();
String banned = System.getProperty("syndie.bannedBlogs", "");
return (banned.indexOf(str) >= 0);

View File

@@ -163,8 +163,9 @@ public class ArchiveIndex {
/** list of unique blogs locally known (set of Hash) */
public Set getUniqueBlogs() {
Set rv = new HashSet();
for (int i = 0; i < _blogs.size(); i++)
for (int i = 0; i < _blogs.size(); i++) {
rv.add(getBlog(i));
}
return rv;
}
public List getReplies(BlogURI uri) {
@@ -367,7 +368,10 @@ public class ArchiveIndex {
return;
tok.nextToken();
String keyStr = tok.nextToken();
Hash keyHash = new Hash(Base64.decode(keyStr));
byte k[] = Base64.decode(keyStr);
if ( (k == null) || (k.length != Hash.HASH_LENGTH) )
return; // ignore bad hashes
Hash keyHash = new Hash(k);
String whenStr = tok.nextToken();
long when = getIndexDate(whenStr);
String tag = tok.nextToken();

View File

@@ -641,6 +641,8 @@ public class RemoteArchiveBean {
int newBlogs = 0;
for (Iterator iter = remoteBlogs.iterator(); iter.hasNext(); ) {
Hash blog = (Hash)iter.next();
if ( (blog == null) || (blog.getData() == null) || (blog.getData().length <= 0) )
continue;
if (ignoreBlog(user, blog))
continue;
if (!localBlogs.contains(blog)) {

View File

@@ -14,8 +14,8 @@ package net.i2p;
*
*/
public class CoreVersion {
public final static String ID = "$Revision: 1.56 $ $Date: 2006/03/26 18:23:49 $";
public final static String VERSION = "0.6.1.14";
public final static String ID = "$Revision: 1.57 $ $Date: 2006/04/05 12:08:07 $";
public final static String VERSION = "0.6.1.15";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@@ -188,6 +188,8 @@ public class Rate {
long measuredPeriod = now - _lastCoalesceDate;
if (measuredPeriod < _period - SLACK) {
// no need to coalesce (assuming we only try to do so once per minute)
if (_log.shouldLog(Log.WARN))
_log.warn("not coalescing, measuredPeriod = " + measuredPeriod + " period = " + _period);
return;
}

View File

@@ -1,4 +1,47 @@
$Id: history.txt,v 1.445 2006/04/04 23:40:04 jrandom Exp $
$Id: history.txt,v 1.454 2006/04/12 23:22:07 jrandom Exp $
* 2006-04-13 0.6.1.15 released
2006-04-12 jrandom
* Added a further failsafe against trying to queue up too many messages to
a peer.
2006-04-12 jrandom
* Watch out for failed syndie index fetches (thanks bar!)
2006-04-11 jrandom
* Throttling improvements on SSU - throttle all transmissions to a peer
when we are retransmitting, not just retransmissions. Also, if
we're already retransmitting to a peer, probabalistically tail drop new
messages targetting that peer, based on the estimated wait time before
transmission.
* Fixed the rounding error in the inbound tunnel drop probability.
2006-04-10 jrandom
* Include a combined send/receive graph (good idea cervantes!)
* Proactively drop inbound tunnel requests probabalistically as the
estimated queue time approaches our limit, rather than letting them all
through up to that limit.
2006-04-08 jrandom
* Stat summarization fix (removing the occational holes in the jrobin
graphs)
2006-04-08 jrandom
* Process inbound tunnel requests more efficiently
* Proactively drop inbound tunnel requests if the queue before we'd
process it in is too long (dynamically adjusted by cpu load)
* Adjust the tunnel rejection throttle to reject requeusts when we have to
proactively drop too many requests.
* Display the number of pending inbound tunnel join requests on the router
console (as the "handle backlog")
* Include a few more stats in the default set of graphs
2006-04-06 jrandom
* Fix for a bug in the new irc ping/pong filter (thanks Complication!)
2006-04-06 jrandom
* Fixed a typo in the reply cleanup code
* 2006-04-05 0.6.1.14 released

View File

@@ -1,5 +1,5 @@
<i2p.news date="$Date: 2006/03/26 18:23:54 $">
<i2p.release version="0.6.1.14" date="2006/04/05" minVersion="0.6"
<i2p.news date="$Date: 2006/04/05 12:08:05 $">
<i2p.release version="0.6.1.15" date="2006/04/13" minVersion="0.6"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"

View File

@@ -4,7 +4,7 @@
<info>
<appname>i2p</appname>
<appversion>0.6.1.14</appversion>
<appversion>0.6.1.15</appversion>
<authors>
<author name="I2P" email="support@i2p.net"/>
</authors>

View File

@@ -1,5 +1,5 @@
<i2p.news date="$Date: 2006/04/04 22:06:00 $">
<i2p.release version="0.6.1.14" date="2006/04/05" minVersion="0.6"
<i2p.news date="$Date: 2006/04/05 12:08:04 $">
<i2p.release version="0.6.1.15" date="2006/04/13" minVersion="0.6"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
@@ -10,8 +10,7 @@
anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting141"
publiclogs="http://www.i2p.net/meeting141" />
&#149;
2006-04-05: 0.6.1.14 released with important tunnel reliability, ssu, and peer
selection fixes.
2006-04-13: 0.6.1.15 released with helpful tunnel building and ssu improvements.
<br>
&#149;
2006-04-04:

View File

@@ -1087,7 +1087,7 @@ class CoalesceStatsEvent implements SimpleTimer.TimedEvent {
}
}
SimpleTimer.getInstance().addEvent(this, 60*1000);
SimpleTimer.getInstance().addEvent(this, 20*1000);
}
}

View File

@@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
*
*/
public class RouterVersion {
public final static String ID = "$Revision: 1.385 $ $Date: 2006/04/04 23:40:10 $";
public final static String VERSION = "0.6.1.14";
public final static String ID = "$Revision: 1.394 $ $Date: 2006/04/12 23:22:33 $";
public final static String VERSION = "0.6.1.15";
public final static long BUILD = 0;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);

View File

@@ -53,6 +53,7 @@ class RouterWatchdog implements Runnable {
private void dumpStatus() {
if (_log.shouldLog(Log.ERROR)) {
Job cur = _context.jobQueue().getLastJob();
/*
if (cur != null)
_log.error("Most recent job: " + cur);
_log.error("Last job began: "
@@ -61,6 +62,7 @@ class RouterWatchdog implements Runnable {
_log.error("Last job ended: "
+ DataHelper.formatDuration(_context.clock().now()-_context.jobQueue().getLastJobEnd())
+ " ago");
*/
_log.error("Ready and waiting jobs: " + _context.jobQueue().getReadyCount());
_log.error("Job lag: " + _context.jobQueue().getMaxLag());
_log.error("Participating tunnel count: " + _context.tunnelManager().getParticipatingCount());

View File

@@ -56,6 +56,9 @@ public interface TunnelManagerFacade extends Service {
/** When does the last tunnel we are participating in expire? */
public long getLastParticipatingExpiration();
/** count how many inbound tunnel requests we have received but not yet processed */
public int getInboundBuildQueueSize();
/**
* the client connected (or updated their settings), so make sure we have
* the tunnels for them, and whenever necessary, ask them to authorize
@@ -97,6 +100,7 @@ class DummyTunnelManagerFacade implements TunnelManagerFacade {
public void setOutboundSettings(TunnelPoolSettings settings) {}
public void setInboundSettings(Hash client, TunnelPoolSettings settings) {}
public void setOutboundSettings(Hash client, TunnelPoolSettings settings) {}
public int getInboundBuildQueueSize() { return 0; }
public void renderStatusHTML(Writer out) throws IOException {}
public void restart() {}

View File

@@ -123,7 +123,8 @@ public class GarlicMessageBuilder {
long timeFromNow = config.getExpiration() - ctx.clock().now();
if (timeFromNow < 1*1000) {
log.error("Building a message expiring in " + timeFromNow + "ms: " + config, new Exception("created by"));
if (log.shouldLog(Log.WARN))
log.warn("Building a message expiring in " + timeFromNow + "ms: " + config, new Exception("created by"));
return null;
}

View File

@@ -151,7 +151,8 @@ public class OutboundMessageRegistry {
if (oldMsg != null) {
List multi = null;
if (oldMsg instanceof OutNetMessage) {
multi = Collections.synchronizedList(new ArrayList(4));
//multi = Collections.synchronizedList(new ArrayList(4));
multi = new ArrayList(4);
multi.add(oldMsg);
multi.add(msg);
_selectorToMessage.put(sel, multi);
@@ -222,10 +223,12 @@ public class OutboundMessageRegistry {
List msgs = null;
synchronized (_selectorToMessage) {
Object o = _selectorToMessage.remove(sel);
if (o instanceof OutNetMessage)
if (o instanceof OutNetMessage) {
msg = (OutNetMessage)o;
else if (o instanceof List)
msgs = new ArrayList((List)o);
} else if (o instanceof List) {
//msgs = new ArrayList((List)o);
msgs = (List)o;
}
}
if (msg != null) {
synchronized (_activeMessages) {
@@ -239,7 +242,7 @@ public class OutboundMessageRegistry {
_activeMessages.removeAll(msgs);
}
for (int j = 0; j < msgs.size(); j++) {
msg = (OutNetMessage)msgs.get(i);
msg = (OutNetMessage)msgs.get(j);
Job fail = msg.getOnFailedReplyJob();
if (fail != null)
_context.jobQueue().addJob(fail);

View File

@@ -203,6 +203,8 @@ public abstract class TransportImpl implements Transport {
+ msg.getMessageType() + " message with selector " + selector, new Exception("fail cause"));
if (msg.getOnFailedSendJob() != null)
_context.jobQueue().addJob(msg.getOnFailedSendJob());
if (msg.getOnFailedReplyJob() != null)
_context.jobQueue().addJob(msg.getOnFailedReplyJob());
if (selector != null)
_context.messageRegistry().unregisterPending(msg);
log = true;

View File

@@ -61,7 +61,7 @@ public class OutboundMessageFragments {
_context.statManager().createRateStat("udp.sendConfirmVolley", "How many times did fragments need to be sent before ACK", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.sendFailed", "How many sends a failed message was pushed", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.sendAggressiveFailed", "How many volleys was a packet sent before we gave up", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.outboundActiveCount", "How many messages are in the active pool", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.outboundActiveCount", "How many messages are in the peer's active pool", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.sendRejected", "What volley are we on when the peer was throttled (time == message lifetime)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.partialACKReceived", "How many fragments were partially ACKed (time == message lifetime)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.sendSparse", "How many fragments were partially ACKed and hence not resent (time == message lifetime)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });

View File

@@ -10,19 +10,19 @@ import java.util.Map;
import java.net.InetAddress;
import java.net.UnknownHostException;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.OutNetMessage;
import net.i2p.router.Job;
/**
* Contain all of the state about a UDP connection to a peer.
*
*/
public class PeerState {
private I2PAppContext _context;
private RouterContext _context;
private Log _log;
/**
* The peer are we talking to. This should be set as soon as this
@@ -216,7 +216,7 @@ public class PeerState {
/** override the default MTU */
private static final String PROP_DEFAULT_MTU = "i2np.udp.mtu";
public PeerState(I2PAppContext ctx, UDPTransport transport) {
public PeerState(RouterContext ctx, UDPTransport transport) {
_context = ctx;
_log = ctx.logManager().getLog(PeerState.class);
_transport = transport;
@@ -278,6 +278,8 @@ public class PeerState {
_context.statManager().createRateStat("udp.rejectConcurrentActive", "How many messages are currently being sent to the peer when we reject it (period is how many concurrent packets we allow)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.allowConcurrentActive", "How many messages are currently being sent to the peer when we accept it (period is how many concurrent packets we allow)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.rejectConcurrentSequence", "How many consecutive concurrency rejections have we had when we stop rejecting (period is how many concurrent packets we are on)", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.queueDropSize", "How many messages were queued up when it was considered full, causing a tail drop?", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("udp.queueAllowTotalLifetime", "When a peer is retransmitting and we probabalistically allow a new message, what is the sum of the pending message lifetimes? (period is the new message's lifetime)?", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
}
private int getDefaultMTU() {
@@ -874,7 +876,7 @@ public class PeerState {
double retransPct = 0;
if (_packetsTransmitted > 10) {
retransPct = (double)_packetsRetransmitted/(double)_packetsTransmitted;
boolean wantLarge = retransPct < .50d; // heuristic to allow fairly lossy links to use large MTUs
boolean wantLarge = retransPct < .30d; // heuristic to allow fairly lossy links to use large MTUs
if (wantLarge && _mtu != LARGE_MTU) {
if (_context.random().nextLong(_mtuDecreases) <= 0) {
_mtu = LARGE_MTU;
@@ -997,7 +999,6 @@ public class PeerState {
}
public RemoteHostId getRemoteHostId() { return _remoteHostId; }
public int add(OutboundMessageState state) {
if (_dead) {
@@ -1009,10 +1010,54 @@ public class PeerState {
_log.debug("Adding to " + _remotePeer.toBase64() + ": " + state.getMessageId());
List msgs = _outboundMessages;
if (msgs == null) return 0;
int rv = 0;
boolean fail = false;
synchronized (msgs) {
msgs.add(state);
return msgs.size();
rv = msgs.size() + 1;
if (rv > 32) {
// 32 queued messages? to *one* peer? nuh uh.
fail = true;
rv--;
} else if (_retransmitter != null) {
long lifetime = _retransmitter.getLifetime();
long totalLifetime = lifetime;
for (int i = 1; i < msgs.size(); i++) { // skip the first, as thats the retransmitter
OutboundMessageState cur = (OutboundMessageState)msgs.get(i);
totalLifetime += cur.getLifetime();
}
long remaining = -1;
OutNetMessage omsg = state.getMessage();
if (omsg != null)
remaining = omsg.getExpiration() - _context.clock().now();
else
remaining = 10*1000 - state.getLifetime();
if (remaining <= 0)
remaining = 1; // total lifetime will exceed it anyway, guaranteeing failure
float pDrop = totalLifetime / (float)remaining;
pDrop = pDrop * pDrop * pDrop;
if (pDrop >= _context.random().nextFloat()) {
if (_log.shouldLog(Log.WARN))
_log.warn("Proactively tail dropping for " + _remotePeer.toBase64() + " (messages=" + msgs.size()
+ " headLifetime=" + lifetime + " totalLifetime=" + totalLifetime + " curLifetime=" + state.getLifetime()
+ " remaining=" + remaining + " pDrop=" + pDrop + ")");
_context.statManager().addRateData("udp.queueDropSize", msgs.size(), totalLifetime);
fail = true;
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Probabalistically allowing for " + _remotePeer.toBase64() + " (messages=" + msgs.size()
+ " headLifetime=" + lifetime + " totalLifetime=" + totalLifetime + " curLifetime=" + state.getLifetime()
+ " remaining=" + remaining + " pDrop=" + pDrop + ")");
_context.statManager().addRateData("udp.queueAllowTotalLifetime", totalLifetime, lifetime);
msgs.add(state);
}
} else {
msgs.add(state);
}
}
if (fail)
_transport.failed(state, false);
return rv;
}
/** drop all outbound messages */
public void dropOutbound() {
@@ -1202,7 +1247,7 @@ public class PeerState {
* mind bw/cwin throttle, etc)
*
*/
private static final boolean THROTTLE_INITIAL_SEND = false;
private static final boolean THROTTLE_INITIAL_SEND = true;
private static final int SSU_HEADER_SIZE = 46;
static final int UDP_HEADER_SIZE = 8;

View File

@@ -41,6 +41,7 @@ class BuildExecutor implements Runnable {
_context.statManager().createRateStat("tunnel.buildClientReject", "How often a client tunnel is rejected", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildRequestTime", "How long it takes to build a tunnel request", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildRequestZeroHopTime", "How long it takes to build a zero hop tunnel", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.pendingRemaining", "How many inbound requests are pending after a pass (period is how long the pass takes)?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_repoll = false;
_handler = new BuildHandler(ctx, this);
}
@@ -117,11 +118,19 @@ class BuildExecutor implements Runnable {
List wanted = new ArrayList(8);
List pools = new ArrayList(8);
boolean pendingRemaining = false;
int pendingRemaining = 0;
long loopBegin = 0;
long beforeHandleInboundReplies = 0;
long afterHandleInboundReplies = 0;
long afterBuildZeroHop = 0;
long afterBuildReal = 0;
long afterHandleInbound = 0;
while (!_manager.isShutdown()){
loopBegin = System.currentTimeMillis();
try {
_repoll = pendingRemaining; // resets repoll to false unless there are inbound requeusts pending
_repoll = pendingRemaining > 0; // resets repoll to false unless there are inbound requeusts pending
_manager.listPools(pools);
for (int i = 0; i < pools.size(); i++) {
TunnelPool pool = (TunnelPool)pools.get(i);
@@ -130,7 +139,9 @@ class BuildExecutor implements Runnable {
wanted.add(pool);
}
beforeHandleInboundReplies = System.currentTimeMillis();
_handler.handleInboundReplies();
afterHandleInboundReplies = System.currentTimeMillis();
// allowed() also expires timed out requests (for new style requests)
int allowed = allowed();
@@ -140,17 +151,22 @@ class BuildExecutor implements Runnable {
// zero hop ones can run inline
allowed = buildZeroHopTunnels(wanted, allowed);
afterBuildZeroHop = System.currentTimeMillis();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Zero hops built, Allowed: " + allowed + " wanted: " + wanted);
int realBuilt = 0;
TunnelManagerFacade mgr = _context.tunnelManager();
if ( (mgr == null) || (mgr.selectInboundTunnel() == null) || (mgr.selectOutboundTunnel() == null) ) {
// we don't have either inbound or outbound tunnels, so don't bother trying to build
// non-zero-hop tunnels
synchronized (_currentlyBuilding) {
if (!_repoll)
_currentlyBuilding.wait(5*1000+_context.random().nextInt(5*1000));
if (!_repoll) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("No tunnel to build with (allowed=" + allowed + ", wanted=" + wanted.size() + ", pending=" + pendingRemaining + "), wait for a while");
_currentlyBuilding.wait(1*1000+_context.random().nextInt(1*1000));
}
}
} else {
if ( (allowed > 0) && (wanted.size() > 0) ) {
@@ -173,6 +189,7 @@ class BuildExecutor implements Runnable {
_currentlyBuilding.add(cfg);
}
buildTunnel(pool, cfg);
realBuilt++;
// 0hops are taken care of above, these are nonstandard 0hops
//if (cfg.getLength() <= 1)
// i--; //0hop, we can keep going, as there's no worry about throttling
@@ -184,13 +201,13 @@ class BuildExecutor implements Runnable {
}
}
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Nothin' doin, wait for a while");
try {
synchronized (_currentlyBuilding) {
if (!_repoll) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Nothin' doin (allowed=" + allowed + ", wanted=" + wanted.size() + ", pending=" + pendingRemaining + "), wait for a while");
//if (allowed <= 0)
_currentlyBuilding.wait(_context.random().nextInt(5*1000));
_currentlyBuilding.wait(_context.random().nextInt(1*1000));
//else // wanted <= 0
// _currentlyBuilding.wait(_context.random().nextInt(30*1000));
}
@@ -201,8 +218,23 @@ class BuildExecutor implements Runnable {
}
}
afterBuildReal = System.currentTimeMillis();
pendingRemaining = _handler.handleInboundRequests();
afterHandleInbound = System.currentTimeMillis();
if (pendingRemaining > 0)
_context.statManager().addRateData("tunnel.pendingRemaining", pendingRemaining, afterHandleInbound-afterBuildReal);
if (_log.shouldLog(Log.INFO))
_log.info("build loop complete, tot=" + (afterHandleInbound-loopBegin) +
" inReply=" + (afterHandleInboundReplies-beforeHandleInboundReplies) +
" zeroHop=" + (afterBuildZeroHop-afterHandleInboundReplies) +
" real=" + (afterBuildReal-afterBuildZeroHop) +
" in=" + (afterHandleInbound-afterBuildReal) +
" built=" + realBuilt +
" pending=" + pendingRemaining);
wanted.clear();
pools.clear();
} catch (Exception e) {
@@ -300,4 +332,5 @@ class BuildExecutor implements Runnable {
}
List locked_getCurrentlyBuilding() { return _currentlyBuilding; }
public int getInboundBuildQueueSize() { return _handler.getInboundBuildQueueSize(); }
}

View File

@@ -6,6 +6,8 @@ import net.i2p.data.i2np.*;
import net.i2p.router.*;
import net.i2p.router.tunnel.*;
import net.i2p.router.peermanager.TunnelHistory;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.util.Log;
/**
@@ -46,6 +48,7 @@ class BuildHandler {
_context.statManager().createRateStat("tunnel.dropLoad", "How long we had to wait before finally giving up on an inbound request (period is queue count)?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.dropLoadDelay", "How long we had to wait before finally giving up on an inbound request?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.dropLoadBacklog", "How many requests were pending when they were so lagged that we had to drop a new inbound request??", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.dropLoadProactive", "What the estimated queue time was when we dropped an inbound request (period is num pending)", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.handleRemaining", "How many pending inbound requests were left on the queue after one pass?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.receiveRejectionProbabalistic", "How often we are rejected probabalistically?", "Tunnels", new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l });
@@ -64,10 +67,10 @@ class BuildHandler {
private static final int NEXT_HOP_LOOKUP_TIMEOUT = 5*1000;
/**
* Blocking call to handle a few of the pending inbound requests, returning true if
* there are remaining requeusts we skipped over
* Blocking call to handle a few of the pending inbound requests, returning how many
* requests remain after this pass
*/
boolean handleInboundRequests() {
int handleInboundRequests() {
int dropExpired = 0;
List handled = null;
synchronized (_inboundBuildMessages) {
@@ -98,7 +101,7 @@ class BuildHandler {
// now pull off the oldest requests first (we're doing a tail-drop
// when adding)
for (int i = 0; i < toHandle; i++)
for (int i = 0; i < toHandle && _inboundBuildMessages.size() > 0; i++)
handled.add(_inboundBuildMessages.remove(0));
}
}
@@ -139,7 +142,7 @@ class BuildHandler {
int remaining = _inboundBuildMessages.size();
if (remaining > 0)
_context.statManager().addRateData("tunnel.handleRemaining", remaining, 0);
return remaining > 0;
return remaining;
}
}
@@ -364,6 +367,30 @@ class BuildHandler {
}
}
/**
* If we are dropping lots of requests before even trying to handle them,
* I suppose you could call us "overloaded"
*/
private final static int MAX_PROACTIVE_DROPS = 120;
private int countProactiveDrops() {
int dropped = 0;
dropped += countEvents("tunnel.dropLoadProactive", 60*1000);
dropped += countEvents("tunnel.dropLoad", 60*1000);
dropped += countEvents("tunnel.dropLoadBacklog", 60*1000);
dropped += countEvents("tunnel.dropLoadDelay", 60*1000);
return dropped;
}
private int countEvents(String stat, long period) {
RateStat rs = _context.statManager().getRate(stat);
if (rs != null) {
Rate r = rs.getRate(period);
if (r != null)
return (int)r.getCurrentEventCount();
}
return 0;
}
private void handleReq(RouterInfo nextPeerInfo, BuildMessageState state, BuildRequestRecord req, Hash nextPeer) {
long ourId = req.readReceiveTunnelId();
long nextId = req.readNextTunnelId();
@@ -384,17 +411,21 @@ class BuildHandler {
//if ( (response == 0) && (_context.random().nextInt(50) <= 1) )
// response = TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT;
int proactiveDrops = countProactiveDrops();
long recvDelay = System.currentTimeMillis()-state.recvTime;
if ( (response == 0) && (recvDelay > BuildRequestor.REQUEST_TIMEOUT/2) ) {
_context.statManager().addRateData("tunnel.rejectOverloaded", recvDelay, recvDelay);
response = TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD;
if ( (response == 0) && ( (recvDelay > BuildRequestor.REQUEST_TIMEOUT/2) || (proactiveDrops > MAX_PROACTIVE_DROPS) ) ) {
_context.statManager().addRateData("tunnel.rejectOverloaded", recvDelay, proactiveDrops);
if (true || (proactiveDrops < MAX_PROACTIVE_DROPS*2))
response = TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD;
else
response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
} else if (response == 0) {
_context.statManager().addRateData("tunnel.acceptLoad", recvDelay, recvDelay);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Responding to " + state.msg.getUniqueId() + "/" + ourId
+ " after " + recvDelay + " with " + response
+ " after " + recvDelay + "/" + proactiveDrops + " with " + response
+ " from " + (state.fromHash != null ? state.fromHash.toBase64() :
state.from != null ? state.from.calculateHash().toBase64() : "tunnel"));
@@ -505,6 +536,12 @@ class BuildHandler {
}
}
public int getInboundBuildQueueSize() {
synchronized (_inboundBuildMessages) {
return _inboundBuildMessages.size();
}
}
private static final boolean HANDLE_REPLIES_INLINE = true;
private class TunnelBuildMessageHandlerJobBuilder implements HandlerJobBuilder {
@@ -551,22 +588,29 @@ class BuildHandler {
synchronized (_inboundBuildMessages) {
boolean removed = false;
int dropped = 0;
while (_inboundBuildMessages.size() > 0) {
BuildMessageState cur = (BuildMessageState)_inboundBuildMessages.get(_inboundBuildMessages.size()-1);
for (int i = 0; i < _inboundBuildMessages.size(); i++) {
BuildMessageState cur = (BuildMessageState)_inboundBuildMessages.get(i);
long age = System.currentTimeMillis() - cur.recvTime;
if (age >= BuildRequestor.REQUEST_TIMEOUT) {
_inboundBuildMessages.remove(_inboundBuildMessages.size()-1);
_inboundBuildMessages.remove(i);
i--;
dropped++;
_context.statManager().addRateData("tunnel.dropLoad", age, _inboundBuildMessages.size());
} else {
break;
}
}
if (dropped > 0) {
// if the queue is backlogged, stop adding new messages
_context.statManager().addRateData("tunnel.dropLoadBacklog", _inboundBuildMessages.size(), _inboundBuildMessages.size());
} else {
_inboundBuildMessages.add(new BuildMessageState(receivedMessage, from, fromHash));
int queueTime = estimateQueueTime(_inboundBuildMessages.size());
float pDrop = queueTime/((float)BuildRequestor.REQUEST_TIMEOUT/2);
pDrop = pDrop * pDrop;
float f = _context.random().nextFloat();
if (pDrop > f) {
_context.statManager().addRateData("tunnel.dropLoadProactive", queueTime, _inboundBuildMessages.size());
} else {
_inboundBuildMessages.add(new BuildMessageState(receivedMessage, from, fromHash));
}
}
}
_exec.repoll();
@@ -576,6 +620,28 @@ class BuildHandler {
}
}
private int estimateQueueTime(int numPendingMessages) {
int decryptTime = 200;
RateStat rs = _context.statManager().getRate("crypto.elGamal.decrypt");
if (rs != null) {
Rate r = rs.getRate(60*1000);
double avg = 0;
if (r != null)
avg = r.getAverageValue();
if (avg > 0) {
decryptTime = (int)avg;
} else {
avg = rs.getLifetimeAverageValue();
if (avg > 0)
decryptTime = (int)avg;
}
}
int estimatedQueueTime = numPendingMessages * decryptTime;
estimatedQueueTime *= 2; // lets leave some cpu to spare, 'eh?
return estimatedQueueTime;
}
private class TunnelBuildReplyMessageHandlerJobBuilder implements HandlerJobBuilder {
public Job createJob(I2NPMessage receivedMessage, RouterIdentity from, Hash fromHash) {
if (_log.shouldLog(Log.DEBUG))

View File

@@ -8,10 +8,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.TunnelId;
import net.i2p.data.*;
import net.i2p.data.i2np.*;
import net.i2p.stat.RateStat;
import net.i2p.router.*;
@@ -390,6 +387,9 @@ public class TunnelPoolManager implements TunnelManagerFacade {
void tunnelFailed() { _executor.repoll(); }
BuildExecutor getExecutor() { return _executor; }
boolean isShutdown() { return _isShutdown; }
public int getInboundBuildQueueSize() { return _executor.getInboundBuildQueueSize(); }
public void renderStatusHTML(Writer out) throws IOException {
out.write("<h2><a name=\"exploratory\">Exploratory tunnels</a> (<a href=\"/configtunnels.jsp#exploratory\">config</a>):</h2>\n");
@@ -499,7 +499,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
if (_context.routerHash().equals(peer))
out.write("<td><i>" + peer.toBase64().substring(0,4) + (id == null ? "" : ":" + id) + "</i></td>");
else
out.write("<td>" + peer.toBase64().substring(0,4) + (id == null ? "" : ":" + id) + "</td>");
out.write("<td>" + peer.toBase64().substring(0,4) + (id == null ? "" : ":" + id) + "</td>");
}
out.write("</tr>\n");