diff --git a/history.txt b/history.txt index 9c0217bd0..748a71236 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,9 @@ +2008-03-27 zzz + * Send messages for the same destination to the same inbound + lease to reduce out-of-order delivery. + * ExploratoryPeerSelector: Back out the floodfill peer exclusion + for now, as it prevents speed rating of those peers + 2008-03-26 zzz * ReseedHandler: Support multiple urls, add netdb.i2p2.de as a 2nd default diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index e0c9f007a..750dae67c 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -17,7 +17,7 @@ import net.i2p.CoreVersion; public class RouterVersion { public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $"; public final static String VERSION = "0.6.1.32"; - public final static long BUILD = 12; + public final static long BUILD = 13; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java index c66c83ede..d4c599e25 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java @@ -199,7 +199,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } } - /** send a message to a random lease */ + /** send a message to a lease */ private class SendJob extends JobImpl { public SendJob(RouterContext enclosingContext) { super(enclosingContext); @@ -222,11 +222,20 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } /** + * Use the same inbound tunnel (i.e. lease) as we did for the same destination previously, + * if possible, to keep the streaming lib happy + * Key the cache just on the dest, not on source+dest, as different sources + * simultaneously talking to the same dest is probably rare enough + * to not bother separating out. + * + * If not found, * fetch the next lease that we should try sending through, randomly chosen - * from within the sorted leaseSet (sorted by # of failures through each + * from within the sorted leaseSet (NOT sorted by # of failures through each * lease). * */ + private static HashMap _leaseCache = new HashMap(); + private static long _lcleanTime = 0; private boolean getNextLease() { _leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash()); if (_leaseSet == null) { @@ -236,6 +245,26 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } long now = getContext().clock().now(); + // Use the same lease if it's still good + synchronized (_leaseCache) { + if (now - _cleanTime > 5*60*1000) { // clean out periodically + cleanLeaseCache(_leaseCache); + _cleanTime = now; + } + _lease = (Lease) _leaseCache.get(_to); + if (_lease != null) { + if (!_lease.isExpired()) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Found in cache - lease for dest " + _to.calculateHash().toBase64()); + return true; + } else { + if (_log.shouldLog(Log.WARN)) + _log.warn("Expired from cache - lease for dest " + _to.calculateHash().toBase64()); + _leaseCache.remove(_to); + } + } + } + // get the possible leases List leases = new ArrayList(_leaseSet.getLeaseCount()); for (int i = 0; i < _leaseSet.getLeaseCount(); i++) { @@ -255,9 +284,6 @@ public class OutboundClientMessageOneShotJob extends JobImpl { return false; } - // Right here is where we should use a persistent lease and caching like - // we do for outbound tunnel selection below??? - // randomize the ordering (so leases with equal # of failures per next // sort are randomly ordered) Collections.shuffle(leases); @@ -277,11 +303,13 @@ public class OutboundClientMessageOneShotJob extends JobImpl { _lease = (Lease)orderedLeases.get(orderedLeases.firstKey()); } else { - // strangely, _lease isn't used anywhere except for log messages - ?!?!??!?!?! - // Apparently the outbound endpoint gets to pick the inbound gateway - // and this whole function is pointless. _lease = (Lease)leases.get(0); } + synchronized (_leaseCache) { + _leaseCache.put(_to, _lease); + } + if (_log.shouldLog(Log.WARN)) + _log.warn("Added to cache - lease for dest " + _to.calculateHash().toBase64()); return true; } @@ -441,6 +469,24 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } } + /** + * Clean out old leases from a set. + * Caller must synchronize on tc. + */ + private void cleanLeaseCache(HashMap tc) { + List deleteList = new ArrayList(); + for (Iterator iter = tc.keySet().iterator(); iter.hasNext(); ) { + Destination dest = (Destination) iter.next(); + Lease l = (Lease) tc.get(dest); + if (l.isExpired()) + deleteList.add(dest); + } + for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) { + Destination dest = (Destination) iter.next(); + tc.remove(dest); + } + } + /** * Clean out old tunnels from a set. * Caller must synchronize on tc. diff --git a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java index 2daf1f6b3..c6a48b0c8 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java @@ -33,8 +33,10 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { Set exclude = getExclude(ctx, settings.isInbound(), settings.isExploratory()); exclude.add(ctx.routerHash()); // Don't use ff peers for exploratory tunnels to lessen exposure to netDb searches and stores - FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb(); - exclude.addAll(fac.getFloodfillPeers()); + // Hmm if they don't get explored they don't get a speed/capacity rating + // so they don't get used for client tunnels either. + // FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade)ctx.netDb(); + // exclude.addAll(fac.getFloodfillPeers()); HashSet matches = new HashSet(length); boolean exploreHighCap = shouldPickHighCap(ctx); if (exploreHighCap)