2006-02-22 jrandom

* Fix to properly profile tunnel joins (thanks Ragnarok, frosk, et al!)
    * More aggressive poor-man's PMTU, allowing larger MTUs on less reliable
      links
    * Further class validator refactorings
This commit is contained in:
jrandom
2006-02-23 01:48:47 +00:00
committed by zzz
parent 03f509ca54
commit 7bb792836d
4 changed files with 188 additions and 173 deletions

View File

@ -153,7 +153,7 @@ public class Router {
shutdown(EXIT_OOM); shutdown(EXIT_OOM);
} }
}; };
_shutdownHook = new ShutdownHook(); _shutdownHook = new ShutdownHook(_context);
_gracefulShutdownDetector = new I2PThread(new GracefulShutdown()); _gracefulShutdownDetector = new I2PThread(new GracefulShutdown());
_gracefulShutdownDetector.setDaemon(true); _gracefulShutdownDetector.setDaemon(true);
_gracefulShutdownDetector.setName("Graceful shutdown hook"); _gracefulShutdownDetector.setName("Graceful shutdown hook");
@ -210,7 +210,7 @@ public class Router {
public void setRouterInfo(RouterInfo info) { public void setRouterInfo(RouterInfo info) {
_routerInfo = info; _routerInfo = info;
if (info != null) if (info != null)
_context.jobQueue().addJob(new PersistRouterInfoJob()); _context.jobQueue().addJob(new PersistRouterInfoJob(_context));
} }
/** /**
@ -245,8 +245,8 @@ public class Router {
_context.tunnelDispatcher().startup(); _context.tunnelDispatcher().startup();
_context.inNetMessagePool().startup(); _context.inNetMessagePool().startup();
startupQueue(); startupQueue();
_context.jobQueue().addJob(new CoalesceStatsJob()); _context.jobQueue().addJob(new CoalesceStatsJob(_context));
_context.jobQueue().addJob(new UpdateRoutingKeyModifierJob()); _context.jobQueue().addJob(new UpdateRoutingKeyModifierJob(_context));
warmupCrypto(); warmupCrypto();
_sessionKeyPersistenceHelper.startup(); _sessionKeyPersistenceHelper.startup();
//_context.adminManager().startup(); //_context.adminManager().startup();
@ -449,89 +449,6 @@ public class Router {
finalShutdown(EXIT_HARD_RESTART); finalShutdown(EXIT_HARD_RESTART);
} }
/**
* coalesce the stats framework every minute
*
*/
private final class CoalesceStatsJob extends JobImpl {
public CoalesceStatsJob() {
super(Router.this._context);
Router.this._context.statManager().createRateStat("bw.receiveBps", "How fast we receive data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
Router.this._context.statManager().createRateStat("bw.sendBps", "How fast we send data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
Router.this._context.statManager().createRateStat("router.activePeers", "How many peers we are actively talking with", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
Router.this._context.statManager().createRateStat("router.highCapacityPeers", "How many high capacity peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
Router.this._context.statManager().createRateStat("router.fastPeers", "How many fast peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
}
public String getName() { return "Coalesce stats"; }
public void runJob() {
Router.this._context.statManager().coalesceStats();
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
if (receiveRate != null) {
Rate rate = receiveRate.getRate(60*1000);
if (rate != null) {
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
Router.this._context.statManager().addRateData("bw.receiveBps", (long)bps, 60*1000);
}
}
RateStat sendRate = _context.statManager().getRate("transport.sendMessageSize");
if (sendRate != null) {
Rate rate = sendRate.getRate(60*1000);
if (rate != null) {
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
Router.this._context.statManager().addRateData("bw.sendBps", (long)bps, 60*1000);
}
}
int active = Router.this._context.commSystem().countActivePeers();
Router.this._context.statManager().addRateData("router.activePeers", active, 60*1000);
int fast = Router.this._context.profileOrganizer().countFastPeers();
Router.this._context.statManager().addRateData("router.fastPeers", fast, 60*1000);
int highCap = Router.this._context.profileOrganizer().countHighCapacityPeers();
Router.this._context.statManager().addRateData("router.highCapacityPeers", highCap, 60*1000);
requeue(60*1000);
}
}
/**
* Update the routing Key modifier every day at midnight (plus on startup).
* This is done here because we want to make sure the key is updated before anyone
* uses it.
*/
private final class UpdateRoutingKeyModifierJob extends JobImpl {
private Calendar _cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
public UpdateRoutingKeyModifierJob() { super(Router.this._context); }
public String getName() { return "Update Routing Key Modifier"; }
public void runJob() {
Router.this._context.routingKeyGenerator().generateDateBasedModData();
requeue(getTimeTillMidnight());
}
private long getTimeTillMidnight() {
long now = Router.this._context.clock().now();
_cal.setTime(new Date(now));
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR)); // gcj <= 4.0 workaround
_cal.set(Calendar.DAY_OF_YEAR, _cal.get(Calendar.DAY_OF_YEAR)); // gcj <= 4.0 workaround
_cal.add(Calendar.DATE, 1);
_cal.set(Calendar.HOUR_OF_DAY, 0);
_cal.set(Calendar.MINUTE, 0);
_cal.set(Calendar.SECOND, 0);
_cal.set(Calendar.MILLISECOND, 0);
long then = _cal.getTime().getTime();
long howLong = then - now;
if (howLong < 0) // hi kaffe
howLong = 24*60*60*1000l + howLong;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Time till midnight: " + howLong + "ms");
return howLong;
}
}
private void warmupCrypto() { private void warmupCrypto() {
_context.random().nextBoolean(); _context.random().nextBoolean();
new DHSessionKeyBuilder(); // load the class so it starts the precalc process new DHSessionKeyBuilder(); // load the class so it starts the precalc process
@ -1060,7 +977,7 @@ public class Router {
return _context.getProperty("router.pingFile", "router.ping"); return _context.getProperty("router.pingFile", "router.ping");
} }
private static final long LIVELINESS_DELAY = 60*1000; static final long LIVELINESS_DELAY = 60*1000;
/** /**
* Start a thread that will periodically update the file "router.ping", but if * Start a thread that will periodically update the file "router.ping", but if
@ -1082,84 +999,177 @@ public class Router {
} }
} }
// not an I2PThread for context creation issues // not an I2PThread for context creation issues
Thread t = new Thread(new MarkLiveliness(f)); Thread t = new Thread(new MarkLiveliness(_context, this, f));
t.setName("Mark router liveliness"); t.setName("Mark router liveliness");
t.setDaemon(true); t.setDaemon(true);
t.start(); t.start();
return true; return true;
} }
}
private class MarkLiveliness implements Runnable {
private File _pingFile; /**
public MarkLiveliness(File f) { * coalesce the stats framework every minute
_pingFile = f; *
} */
public void run() { class CoalesceStatsJob extends JobImpl {
_pingFile.deleteOnExit(); public CoalesceStatsJob(RouterContext ctx) {
do { super(ctx);
ping(); ctx.statManager().createRateStat("bw.receiveBps", "How fast we receive data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
try { Thread.sleep(LIVELINESS_DELAY); } catch (InterruptedException ie) {} ctx.statManager().createRateStat("bw.sendBps", "How fast we send data", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
} while (_isAlive); ctx.statManager().createRateStat("router.activePeers", "How many peers we are actively talking with", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
_pingFile.delete(); ctx.statManager().createRateStat("router.highCapacityPeers", "How many high capacity peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
} ctx.statManager().createRateStat("router.fastPeers", "How many fast peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 });
}
private void ping() { public String getName() { return "Coalesce stats"; }
FileOutputStream fos = null; public void runJob() {
try { getContext().statManager().coalesceStats();
fos = new FileOutputStream(_pingFile);
fos.write(("" + System.currentTimeMillis()).getBytes()); RateStat receiveRate = getContext().statManager().getRate("transport.receiveMessageSize");
} catch (IOException ioe) { if (receiveRate != null) {
if (_log != null) { Rate rate = receiveRate.getRate(60*1000);
_log.log(Log.CRIT, "Error writing to ping file", ioe); if (rate != null) {
} else { double bytes = rate.getLastTotalValue();
System.err.println("Error writing to ping file"); double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
ioe.printStackTrace(); getContext().statManager().addRateData("bw.receiveBps", (long)bps, 60*1000);
}
} finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
} }
} }
}
private static int __id = 0;
private class ShutdownHook extends Thread {
private int _id;
public ShutdownHook() {
_id = ++__id;
}
public void run() {
setName("Router " + _id + " shutdown");
_log.log(Log.CRIT, "Shutting down the router...");
shutdown(EXIT_HARD);
}
}
/** update the router.info file whenever its, er, updated */
private class PersistRouterInfoJob extends JobImpl {
public PersistRouterInfoJob() { super(Router.this._context); }
public String getName() { return "Persist Updated Router Information"; }
public void runJob() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Persisting updated router info");
String infoFilename = getConfigSetting(PROP_INFO_FILENAME); RateStat sendRate = getContext().statManager().getRate("transport.sendMessageSize");
if (infoFilename == null) if (sendRate != null) {
infoFilename = PROP_INFO_FILENAME_DEFAULT; Rate rate = sendRate.getRate(60*1000);
if (rate != null) {
RouterInfo info = getRouterInfo(); double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
FileOutputStream fos = null; getContext().statManager().addRateData("bw.sendBps", (long)bps, 60*1000);
try {
fos = new FileOutputStream(infoFilename);
info.writeBytes(fos);
} catch (DataFormatException dfe) {
_log.error("Error rebuilding the router information", dfe);
} catch (IOException ioe) {
_log.error("Error writing out the rebuilt router information", ioe);
} finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
} }
} }
int active = getContext().commSystem().countActivePeers();
getContext().statManager().addRateData("router.activePeers", active, 60*1000);
int fast = getContext().profileOrganizer().countFastPeers();
getContext().statManager().addRateData("router.fastPeers", fast, 60*1000);
int highCap = getContext().profileOrganizer().countHighCapacityPeers();
getContext().statManager().addRateData("router.highCapacityPeers", highCap, 60*1000);
requeue(60*1000);
}
}
/**
* Update the routing Key modifier every day at midnight (plus on startup).
* This is done here because we want to make sure the key is updated before anyone
* uses it.
*/
class UpdateRoutingKeyModifierJob extends JobImpl {
private Log _log;
private Calendar _cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
public UpdateRoutingKeyModifierJob(RouterContext ctx) {
super(ctx);
}
public String getName() { return "Update Routing Key Modifier"; }
public void runJob() {
_log = getContext().logManager().getLog(getClass());
getContext().routingKeyGenerator().generateDateBasedModData();
requeue(getTimeTillMidnight());
}
private long getTimeTillMidnight() {
long now = getContext().clock().now();
_cal.setTime(new Date(now));
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR)); // gcj <= 4.0 workaround
_cal.set(Calendar.DAY_OF_YEAR, _cal.get(Calendar.DAY_OF_YEAR)); // gcj <= 4.0 workaround
_cal.add(Calendar.DATE, 1);
_cal.set(Calendar.HOUR_OF_DAY, 0);
_cal.set(Calendar.MINUTE, 0);
_cal.set(Calendar.SECOND, 0);
_cal.set(Calendar.MILLISECOND, 0);
long then = _cal.getTime().getTime();
long howLong = then - now;
if (howLong < 0) // hi kaffe
howLong = 24*60*60*1000l + howLong;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Time till midnight: " + howLong + "ms");
return howLong;
}
}
class MarkLiveliness implements Runnable {
private RouterContext _context;
private Router _router;
private File _pingFile;
public MarkLiveliness(RouterContext ctx, Router router, File pingFile) {
_context = ctx;
_router = router;
_pingFile = pingFile;
}
public void run() {
_pingFile.deleteOnExit();
do {
ping();
try { Thread.sleep(Router.LIVELINESS_DELAY); } catch (InterruptedException ie) {}
} while (_router.isAlive());
_pingFile.delete();
}
private void ping() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(_pingFile);
fos.write(("" + System.currentTimeMillis()).getBytes());
} catch (IOException ioe) {
System.err.println("Error writing to ping file");
ioe.printStackTrace();
} finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
}
} }
} }
class ShutdownHook extends Thread {
private RouterContext _context;
private static int __id = 0;
private int _id;
public ShutdownHook(RouterContext ctx) {
_context = ctx;
_id = ++__id;
}
public void run() {
setName("Router " + _id + " shutdown");
Log l = _context.logManager().getLog(Router.class);
l.log(Log.CRIT, "Shutting down the router...");
_context.router().shutdown(Router.EXIT_HARD);
}
}
/** update the router.info file whenever its, er, updated */
class PersistRouterInfoJob extends JobImpl {
private Log _log;
public PersistRouterInfoJob(RouterContext ctx) {
super(ctx);
}
public String getName() { return "Persist Updated Router Information"; }
public void runJob() {
_log = getContext().logManager().getLog(PersistRouterInfoJob.class);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Persisting updated router info");
String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME);
if (infoFilename == null)
infoFilename = Router.PROP_INFO_FILENAME_DEFAULT;
RouterInfo info = getContext().router().getRouterInfo();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(infoFilename);
info.writeBytes(fos);
} catch (DataFormatException dfe) {
_log.error("Error rebuilding the router information", dfe);
} catch (IOException ioe) {
_log.error("Error writing out the rebuilt router information", ioe);
} finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
}
}
}

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
* *
*/ */
public class RouterVersion { public class RouterVersion {
public final static String ID = "$Revision: 1.356 $ $Date: 2006/02/21 10:20:20 $"; public final static String ID = "$Revision: 1.357 $ $Date: 2006/02/22 09:54:23 $";
public final static String VERSION = "0.6.1.11"; public final static String VERSION = "0.6.1.11";
public final static long BUILD = 1; public final static long BUILD = 2;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -835,13 +835,7 @@ public class PeerState {
_messagesSent++; _messagesSent++;
if (numSends < 2) { if (numSends < 2) {
recalculateTimeouts(lifetime); recalculateTimeouts(lifetime);
if (_mtu <= MIN_MTU) { adjustMTU();
if (_context.random().nextInt(50*(int)_mtuDecreases) <= 0) {
_context.statManager().addRateData("udp.mtuIncrease", _packetsRetransmitted, _packetsTransmitted);
_mtu = LARGE_MTU;
_mtuIncreases++;
}
}
} }
else if (_log.shouldLog(Log.WARN)) else if (_log.shouldLog(Log.WARN))
_log.warn("acked after numSends=" + numSends + " w/ lifetime=" + lifetime + " and size=" + bytesACKed); _log.warn("acked after numSends=" + numSends + " w/ lifetime=" + lifetime + " and size=" + bytesACKed);
@ -870,14 +864,24 @@ public class PeerState {
_rto = MAX_RTO; _rto = MAX_RTO;
} }
private void reduceMTU() { private void adjustMTU() {
if (_mtu > MIN_MTU) { double retransPct = 0;
double retransPct = (double)_packetsRetransmitted/(double)_packetsTransmitted; if (_packetsTransmitted > 0) {
if (retransPct >= 0.05) { // should we go for lower? retransPct = (double)_packetsRetransmitted/(double)_packetsTransmitted;
_context.statManager().addRateData("udp.mtuDecrease", _packetsRetransmitted, _packetsTransmitted); boolean wantLarge = retransPct < .25d; // heuristic to allow fairly lossy links to use large MTUs
if (wantLarge && _mtu != LARGE_MTU) {
if (_context.random().nextLong(_mtuDecreases) <= 0) {
_mtu = LARGE_MTU;
_mtuIncreases++;
_context.statManager().addRateData("udp.mtuIncrease", _mtuIncreases, _mtuDecreases);
}
} else if (!wantLarge && _mtu == LARGE_MTU) {
_mtu = MIN_MTU; _mtu = MIN_MTU;
_mtuDecreases++; _mtuDecreases++;
} _context.statManager().addRateData("udp.mtuDecrease", _mtuDecreases, _mtuIncreases);
}
} else {
_mtu = DEFAULT_MTU;
} }
} }
@ -895,7 +899,7 @@ public class PeerState {
} }
congestionOccurred(); congestionOccurred();
_context.statManager().addRateData("udp.congestedRTO", _rto, _rttDeviation); _context.statManager().addRateData("udp.congestedRTO", _rto, _rttDeviation);
reduceMTU(); adjustMTU();
//_rto *= 2; //_rto *= 2;
} }
public void packetsTransmitted(int packets) { public void packetsTransmitted(int packets) {

View File

@ -188,6 +188,7 @@ class BuildHandler {
if (howBad == 0) { if (howBad == 0) {
// w3wt // w3wt
_context.profileManager().tunnelJoined(peer, rtt);
} else { } else {
allAgree = false; allAgree = false;
switch (howBad) { switch (howBad) {