From 97da508df541ee755142f3805aaac4c124852977 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 24 Oct 2012 17:38:20 +0000 Subject: [PATCH] * I2PSnark: - Fix (again) partial piece avoidance for seeds - Fix several partial piece (temp file) leaks, some uncovered by previous rarest-first fixes, some in end game - Don't lose all DHT peers if we stop quickly (backport from update branch) - Explore a kbucket if it's less than 3/4 full (backport from update branch) --- .../java/src/net/i2p/kademlia/KBucketSet.java | 3 ++- .../src/org/klomp/snark/PeerCoordinator.java | 24 ++++++++++++++++--- .../java/src/org/klomp/snark/PeerState.java | 5 ++++ .../java/src/org/klomp/snark/dht/KRPC.java | 4 +++- .../src/org/klomp/snark/dht/PersistDHT.java | 7 ++++-- history.txt | 6 +++++ .../src/net/i2p/router/RouterVersion.java | 2 +- 7 files changed, 43 insertions(+), 8 deletions(-) diff --git a/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java b/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java index 72ca6e574..c242ab9b7 100644 --- a/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java +++ b/apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java @@ -518,6 +518,7 @@ public class KBucketSet { /** * For every bucket that hasn't been updated in this long, + * or isn't close to full, * generate a random key that would be a member of that bucket. * The returned keys may be searched for to "refresh" the buckets. * @return non-null, closest first @@ -528,7 +529,7 @@ public class KBucketSet { getReadLock(); try { for (KBucket b : _buckets) { - if (b.getLastChanged() < old) + if (b.getLastChanged() < old || b.getKeyCount() < BUCKET_SIZE * 3 / 4) rv.add(generateRandomKey(b)); } } finally { releaseReadLock(); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 8ffde7363..43240dea1 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -741,7 +741,19 @@ class PeerCoordinator implements PeerListener break; if (havePieces.get(p.getId()) && !p.isRequested()) { - piece = p; + // never ever choose one that's in partialPieces, or we + // will create a second one and leak + boolean hasPartial = false; + for (PartialPiece pp : partialPieces) { + if (pp.getPiece() == p.getId()) { + if (_log.shouldLog(Log.INFO)) + _log.info("wantPiece() skipping partial for " + peer + ": piece = " + pp); + hasPartial = true; + break; + } + } + if (!hasPartial) + piece = p; } else if (p.isRequested()) { @@ -943,11 +955,14 @@ class PeerCoordinator implements PeerListener */ public boolean gotPiece(Peer peer, PartialPiece pp) { - if (metainfo == null || storage == null) + if (metainfo == null || storage == null) { + pp.release(); return true; + } int piece = pp.getPiece(); if (halted) { _log.info("Got while-halted piece " + piece + "/" + metainfo.getPieces() +" from " + peer + " for " + metainfo.getName()); + pp.release(); return true; // We don't actually care anymore. } @@ -962,8 +977,10 @@ class PeerCoordinator implements PeerListener // Assume we got a good piece, we don't really care anymore. // Well, this could be caused by a change in priorities, so // only return true if we already have it, otherwise might as well keep it. - if (storage.getBitField().get(piece)) + if (storage.getBitField().get(piece)) { + pp.release(); return true; + } } try @@ -1277,6 +1294,7 @@ class PeerCoordinator implements PeerListener PartialPiece pp = iter.next(); if (pp.getPiece() == piece) { iter.remove(); + pp.release(); // there should be only one but keep going to be sure } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index 95bef3c4f..8add00d2b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -592,6 +592,7 @@ class PeerState implements DataLoader // Send cancel even when we are choked to make sure that it is // really never ever send. out.sendCancel(req); + req.getPartialPiece().release(); } } } @@ -741,6 +742,10 @@ class PeerState implements DataLoader out.sendRequest(r); lastRequest = r; return true; + } else { + if (_log.shouldLog(Log.WARN)) + _log.warn("Got dup from coord: " + pp); + pp.release(); } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java index 6dd9572d6..01a63a259 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java +++ b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java @@ -572,7 +572,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT { _session.removeListener(I2PSession.PROTO_DATAGRAM_RAW, _rPort); // clear the DHT and tracker _tracker.stop(); - PersistDHT.saveDHT(_knownNodes, _dhtFile); + // don't lose all our peers if we didn't have time to check them + boolean saveAll = _context.clock().now() - _started < 20*60*1000; + PersistDHT.saveDHT(_knownNodes, saveAll, _dhtFile); _knownNodes.stop(); for (Iterator iter = _sentQueries.values().iterator(); iter.hasNext(); ) { ReplyWaiter waiter = iter.next(); diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/PersistDHT.java b/apps/i2psnark/java/src/org/klomp/snark/dht/PersistDHT.java index f474e1dd0..7ad643d91 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/dht/PersistDHT.java +++ b/apps/i2psnark/java/src/org/klomp/snark/dht/PersistDHT.java @@ -56,12 +56,15 @@ abstract class PersistDHT { log.info("Loaded " + count + " nodes from " + file); } - public static synchronized void saveDHT(DHTNodes nodes, File file) { + /** + * @param saveAll if true, don't check last seen time + */ + public static synchronized void saveDHT(DHTNodes nodes, boolean saveAll, File file) { if (nodes.size() <= 0) return; Log log = I2PAppContext.getGlobalContext().logManager().getLog(PersistDHT.class); int count = 0; - long maxAge = I2PAppContext.getGlobalContext().clock().now() - MAX_AGE; + long maxAge = saveAll ? 0 : I2PAppContext.getGlobalContext().clock().now() - MAX_AGE; PrintWriter out = null; try { out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "ISO-8859-1"))); diff --git a/history.txt b/history.txt index 4d551affa..6e45128aa 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,9 @@ +2012-10-24 zzz + * I2PSnark: + - Fix several partial piece (temp file) leaks + - Don't lose all DHT peers if we stop quickly + - Explore a kbucket if it's less than 3/4 full + 2012-10-24 str4d * i2ptunnel: Truncate long client destinations (ticket #581) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 14408f1ed..987fc2f75 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 18; + public final static long BUILD = 19; /** for example "-test" */ public final static String EXTRA = "-rc";