forked from I2P_Developers/i2p.i2p
* i2psnark:
- Reduce TrackerClient threads - Reduce delay between peer adds for faster startup - Thread the announces and reduce timeout when stopping
This commit is contained in:
@ -68,6 +68,8 @@ public class I2PSnarkUtil {
|
|||||||
private List<String> _openTrackers;
|
private List<String> _openTrackers;
|
||||||
private DHT _dht;
|
private DHT _dht;
|
||||||
|
|
||||||
|
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
|
||||||
|
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
|
||||||
public static final int DEFAULT_STARTUP_DELAY = 3;
|
public static final int DEFAULT_STARTUP_DELAY = 3;
|
||||||
public static final boolean DEFAULT_USE_OPENTRACKERS = true;
|
public static final boolean DEFAULT_USE_OPENTRACKERS = true;
|
||||||
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
|
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
|
||||||
@ -306,11 +308,24 @@ public class I2PSnarkUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fetch the given URL, returning the file it is stored in, or null on error
|
* Fetch the given URL, returning the file it is stored in, or null on error.
|
||||||
|
* No retries.
|
||||||
*/
|
*/
|
||||||
public File get(String url) { return get(url, true, 0); }
|
public File get(String url) { return get(url, true, 0); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rewrite if true, convert http://KEY.i2p/foo/announce to http://i2p/KEY/foo/announce
|
||||||
|
*/
|
||||||
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
|
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param retries if < 0, set timeout to a few seconds
|
||||||
|
*/
|
||||||
public File get(String url, int retries) { return get(url, true, retries); }
|
public File get(String url, int retries) { return get(url, true, retries); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param retries if < 0, set timeout to a few seconds
|
||||||
|
*/
|
||||||
public File get(String url, boolean rewrite, int retries) {
|
public File get(String url, boolean rewrite, int retries) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
||||||
@ -331,12 +346,21 @@ public class I2PSnarkUtil {
|
|||||||
//_log.debug("Rewritten url [" + fetchURL + "]");
|
//_log.debug("Rewritten url [" + fetchURL + "]");
|
||||||
//EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
|
//EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
|
||||||
// Use our tunnel for announces and .torrent fetches too! Make sure we're connected first...
|
// Use our tunnel for announces and .torrent fetches too! Make sure we're connected first...
|
||||||
|
int timeout;
|
||||||
|
if (retries < 0) {
|
||||||
|
if (!connected())
|
||||||
|
return null;
|
||||||
|
timeout = EEPGET_CONNECT_TIMEOUT_SHORT;
|
||||||
|
retries = 0;
|
||||||
|
} else {
|
||||||
|
timeout = EEPGET_CONNECT_TIMEOUT;
|
||||||
if (!connected()) {
|
if (!connected()) {
|
||||||
if (!connect())
|
if (!connect())
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
|
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
|
||||||
if (get.fetch()) {
|
if (get.fetch(timeout)) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
||||||
return out;
|
return out;
|
||||||
|
@ -231,8 +231,8 @@ class PeerState implements DataLoader
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.info("Queueing (" + piece + ", " + begin + ", "
|
_log.debug("Queueing (" + piece + ", " + begin + ", "
|
||||||
+ length + ")" + " to " + peer);
|
+ length + ")" + " to " + peer);
|
||||||
|
|
||||||
// don't load the data into mem now, let PeerConnectionOut do it
|
// don't load the data into mem now, let PeerConnectionOut do it
|
||||||
@ -267,8 +267,8 @@ class PeerState implements DataLoader
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.info("Sending (" + piece + ", " + begin + ", "
|
_log.debug("Sending (" + piece + ", " + begin + ", "
|
||||||
+ length + ")" + " to " + peer);
|
+ length + ")" + " to " + peer);
|
||||||
return pieceBytes;
|
return pieceBytes;
|
||||||
}
|
}
|
||||||
|
@ -567,10 +567,6 @@ public class Snark
|
|||||||
fatal("Could not reopen storage", ioe);
|
fatal("Could not reopen storage", ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TrackerClient newClient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this);
|
|
||||||
if (!trackerclient.halted())
|
|
||||||
trackerclient.halt();
|
|
||||||
trackerclient = newClient;
|
|
||||||
trackerclient.start();
|
trackerclient.start();
|
||||||
} else {
|
} else {
|
||||||
debug("NOT starting TrackerClient???", NOTICE);
|
debug("NOT starting TrackerClient???", NOTICE);
|
||||||
|
@ -1596,8 +1596,10 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
Set names = listTorrentFiles();
|
Set names = listTorrentFiles();
|
||||||
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
|
||||||
Snark snark = getTorrent((String)iter.next());
|
Snark snark = getTorrent((String)iter.next());
|
||||||
if ( (snark != null) && (!snark.isStopped()) )
|
if ( (snark != null) && (!snark.isStopped()) ) {
|
||||||
snark.stopTorrent();
|
snark.stopTorrent();
|
||||||
|
try { Thread.sleep(50); } catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,18 +35,32 @@ import java.util.Random;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.util.Clock;
|
||||||
import net.i2p.util.I2PAppThread;
|
import net.i2p.util.I2PAppThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.SimpleTimer2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Informs metainfo tracker of events and gets new peers for peer
|
* Informs metainfo tracker of events and gets new peers for peer
|
||||||
* coordinator.
|
* coordinator.
|
||||||
*
|
*
|
||||||
|
* start() creates a thread and starts it.
|
||||||
|
* At the end of each run, a TimedEvent is queued on the SimpleTimer2 queue.
|
||||||
|
* The TimedEvent creates a new thread and starts it, so it does not
|
||||||
|
* clog SimpleTimer2.
|
||||||
|
*
|
||||||
|
* The thread runs one pass through the trackers, the PEX, and the DHT,
|
||||||
|
* then queues a new TimedEvent and exits.
|
||||||
|
*
|
||||||
|
* Thus there are only threads that are actively announcing, not one thread per torrent forever.
|
||||||
|
*
|
||||||
|
* start() may be called again after halt().
|
||||||
|
*
|
||||||
* @author Mark Wielaard (mark@klomp.org)
|
* @author Mark Wielaard (mark@klomp.org)
|
||||||
*/
|
*/
|
||||||
public class TrackerClient extends I2PAppThread
|
public class TrackerClient implements Runnable {
|
||||||
{
|
|
||||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(TrackerClient.class);
|
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(TrackerClient.class);
|
||||||
private static final String NO_EVENT = "";
|
private static final String NO_EVENT = "";
|
||||||
private static final String STARTED_EVENT = "started";
|
private static final String STARTED_EVENT = "started";
|
||||||
@ -56,25 +70,39 @@ public class TrackerClient extends I2PAppThread
|
|||||||
|
|
||||||
private final static int SLEEP = 5; // 5 minutes.
|
private final static int SLEEP = 5; // 5 minutes.
|
||||||
private final static int DELAY_MIN = 2000; // 2 secs.
|
private final static int DELAY_MIN = 2000; // 2 secs.
|
||||||
private final static int DELAY_MUL = 1500; // 1.5 secs.
|
private final static int DELAY_RAND = 6*1000;
|
||||||
private final static int MAX_REGISTER_FAILS = 10; // * INITIAL_SLEEP = 15m to register
|
private final static int MAX_REGISTER_FAILS = 10; // * INITIAL_SLEEP = 15m to register
|
||||||
private final static int INITIAL_SLEEP = 90*1000;
|
private final static int INITIAL_SLEEP = 90*1000;
|
||||||
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
|
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
|
||||||
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
|
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
|
||||||
|
|
||||||
private I2PSnarkUtil _util;
|
private final I2PSnarkUtil _util;
|
||||||
private final MetaInfo meta;
|
private final MetaInfo meta;
|
||||||
|
private final String infoHash;
|
||||||
|
private final String peerID;
|
||||||
private final String additionalTrackerURL;
|
private final String additionalTrackerURL;
|
||||||
private final PeerCoordinator coordinator;
|
private final PeerCoordinator coordinator;
|
||||||
private final Snark snark;
|
private final Snark snark;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
private final String _threadName;
|
||||||
|
|
||||||
private boolean stop;
|
private volatile boolean stop = true;
|
||||||
private boolean started;
|
private volatile boolean started;
|
||||||
|
private volatile boolean _initialized;
|
||||||
|
private volatile int _runCount;
|
||||||
|
// running thread so it can be interrupted
|
||||||
|
private volatile Thread _thread;
|
||||||
|
// queued event so it can be cancelled
|
||||||
|
private volatile SimpleTimer2.TimedEvent _event;
|
||||||
|
// these 2 used in loop()
|
||||||
|
private volatile boolean runStarted;
|
||||||
|
private volatile int consecutiveFails;
|
||||||
|
|
||||||
private List<Tracker> trackers;
|
private final List<Tracker> trackers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Call start() to start it.
|
||||||
|
*
|
||||||
* @param meta null if in magnet mode
|
* @param meta null if in magnet mode
|
||||||
* @param additionalTrackerURL may be null, from the ?tr= param in magnet mode, otherwise ignored
|
* @param additionalTrackerURL may be null, from the ?tr= param in magnet mode, otherwise ignored
|
||||||
*/
|
*/
|
||||||
@ -84,7 +112,7 @@ public class TrackerClient extends I2PAppThread
|
|||||||
super();
|
super();
|
||||||
// Set unique name.
|
// Set unique name.
|
||||||
String id = urlencode(snark.getID());
|
String id = urlencode(snark.getID());
|
||||||
setName("TrackerClient " + id.substring(id.length() - 12));
|
_threadName = "TrackerClient " + id.substring(id.length() - 12);
|
||||||
_util = util;
|
_util = util;
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
this.additionalTrackerURL = additionalTrackerURL;
|
this.additionalTrackerURL = additionalTrackerURL;
|
||||||
@ -92,12 +120,22 @@ public class TrackerClient extends I2PAppThread
|
|||||||
this.snark = snark;
|
this.snark = snark;
|
||||||
|
|
||||||
this.port = 6881; //(port == -1) ? 9 : port;
|
this.port = 6881; //(port == -1) ? 9 : port;
|
||||||
|
this.infoHash = urlencode(snark.getInfoHash());
|
||||||
|
this.peerID = urlencode(snark.getID());
|
||||||
|
this.trackers = new ArrayList(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public synchronized void start() {
|
||||||
public void start() {
|
if (!stop) {
|
||||||
if (stop) throw new RuntimeException("Dont rerun me, create a copy");
|
if (_log.shouldLog(Log.WARN))
|
||||||
super.start();
|
_log.warn("Already started: " + _threadName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stop = false;
|
||||||
|
consecutiveFails = 0;
|
||||||
|
runStarted = false;
|
||||||
|
_thread = new I2PAppThread(this, _threadName + " #" + (++_runCount), true);
|
||||||
|
_thread.start();
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,10 +145,47 @@ public class TrackerClient extends I2PAppThread
|
|||||||
/**
|
/**
|
||||||
* Interrupts this Thread to stop it.
|
* Interrupts this Thread to stop it.
|
||||||
*/
|
*/
|
||||||
public void halt()
|
public synchronized void halt() {
|
||||||
{
|
boolean wasStopped = stop;
|
||||||
|
if (wasStopped) {
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Already stopped: " + _threadName);
|
||||||
|
} else {
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Stopping: " + _threadName);
|
||||||
stop = true;
|
stop = true;
|
||||||
this.interrupt();
|
}
|
||||||
|
SimpleTimer2.TimedEvent e = _event;
|
||||||
|
if (e != null) {
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Cancelling next announce " + _threadName);
|
||||||
|
e.cancel();
|
||||||
|
_event = null;
|
||||||
|
}
|
||||||
|
Thread t = _thread;
|
||||||
|
if (t != null) {
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Interrupting " + t.getName());
|
||||||
|
t.interrupt();
|
||||||
|
}
|
||||||
|
if (!wasStopped)
|
||||||
|
unannounce();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queueLoop(long delay) {
|
||||||
|
_event = new Runner(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Runner extends SimpleTimer2.TimedEvent {
|
||||||
|
public Runner(long delay) {
|
||||||
|
super(SimpleTimer2.getInstance(), delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void timeReached() {
|
||||||
|
_event = null;
|
||||||
|
_thread = new I2PAppThread(TrackerClient.this, _threadName + " #" + (++_runCount), true);
|
||||||
|
_thread.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean verifyConnected() {
|
private boolean verifyConnected() {
|
||||||
@ -123,20 +198,51 @@ public class TrackerClient extends I2PAppThread
|
|||||||
return !stop && _util.connected();
|
return !stop && _util.connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void run()
|
* Setup the first time only,
|
||||||
{
|
* then one pass (usually) through the trackers, PEX, and DHT.
|
||||||
String infoHash = urlencode(snark.getInfoHash());
|
* This will take several seconds to several minutes.
|
||||||
String peerID = urlencode(snark.getID());
|
*/
|
||||||
|
public void run() {
|
||||||
|
long begin = Clock.getInstance().now();
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Start " + Thread.currentThread().getName());
|
||||||
|
try {
|
||||||
|
if (!_initialized) {
|
||||||
|
setup();
|
||||||
|
// FIXME dht
|
||||||
|
if (trackers.isEmpty()) {
|
||||||
|
stop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_initialized = true;
|
||||||
|
// FIXME only when starting everybody at once, not for a single torrent
|
||||||
|
long delay = I2PAppContext.getGlobalContext().random().nextInt(30*1000);
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
|
loop();
|
||||||
|
} finally {
|
||||||
|
// don't hold ref
|
||||||
|
_thread = null;
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Finish " + Thread.currentThread().getName() +
|
||||||
|
" after " + DataHelper.formatDuration(Clock.getInstance().now() - begin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do this one time only (not every time it is started).
|
||||||
|
* @since 0.9.1
|
||||||
|
*/
|
||||||
|
public void setup() {
|
||||||
// Construct the list of trackers for this torrent,
|
// Construct the list of trackers for this torrent,
|
||||||
// starting with the primary one listed in the metainfo,
|
// starting with the primary one listed in the metainfo,
|
||||||
// followed by the secondary open trackers
|
// followed by the secondary open trackers
|
||||||
// It's painful, but try to make sure if an open tracker is also
|
// It's painful, but try to make sure if an open tracker is also
|
||||||
// the primary tracker, that we don't add it twice.
|
// the primary tracker, that we don't add it twice.
|
||||||
// todo: check for b32 matches as well
|
// todo: check for b32 matches as well
|
||||||
trackers = new ArrayList(2);
|
|
||||||
String primary = null;
|
String primary = null;
|
||||||
if (meta != null)
|
if (meta != null)
|
||||||
primary = meta.getAnnounce();
|
primary = meta.getAnnounce();
|
||||||
@ -192,58 +298,32 @@ public class TrackerClient extends I2PAppThread
|
|||||||
this.snark.stopTorrent();
|
this.snark.stopTorrent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long uploaded = coordinator.getUploaded();
|
/**
|
||||||
long downloaded = coordinator.getDownloaded();
|
* Announce to all the trackers, get peers from PEX and DHT, then queue up a SimpleTimer2 event.
|
||||||
long left = coordinator.getLeft();
|
* This will take several seconds to several minutes.
|
||||||
|
* @since 0.9.1
|
||||||
boolean completed = (left == 0);
|
*/
|
||||||
|
private void loop() {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!verifyConnected()) return;
|
|
||||||
boolean runStarted = false;
|
|
||||||
boolean firstTime = true;
|
|
||||||
int consecutiveFails = 0;
|
|
||||||
Random r = I2PAppContext.getGlobalContext().random();
|
Random r = I2PAppContext.getGlobalContext().random();
|
||||||
while(!stop)
|
while(!stop)
|
||||||
{
|
{
|
||||||
|
if (!verifyConnected()) {
|
||||||
|
stop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Local DHT tracker announce
|
// Local DHT tracker announce
|
||||||
if (_util.getDHT() != null)
|
if (_util.getDHT() != null)
|
||||||
_util.getDHT().announce(snark.getInfoHash());
|
_util.getDHT().announce(snark.getInfoHash());
|
||||||
try
|
|
||||||
{
|
|
||||||
// Sleep some minutes...
|
|
||||||
// Sleep the minimum interval for all the trackers, but 60s minimum
|
|
||||||
// except for the first time...
|
|
||||||
int delay;
|
|
||||||
int random = r.nextInt(120*1000);
|
|
||||||
if (firstTime) {
|
|
||||||
delay = r.nextInt(30*1000);
|
|
||||||
firstTime = false;
|
|
||||||
} else if (completed && runStarted)
|
|
||||||
delay = 3*SLEEP*60*1000 + random;
|
|
||||||
else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
|
|
||||||
delay = INITIAL_SLEEP;
|
|
||||||
else
|
|
||||||
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
|
|
||||||
delay = SLEEP*60*1000 + random;
|
|
||||||
|
|
||||||
if (delay > 0)
|
long uploaded = coordinator.getUploaded();
|
||||||
Thread.sleep(delay);
|
long downloaded = coordinator.getDownloaded();
|
||||||
}
|
long left = coordinator.getLeft(); // -1 in magnet mode
|
||||||
catch(InterruptedException interrupt)
|
boolean completed = (left == 0);
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!verifyConnected()) return;
|
|
||||||
|
|
||||||
uploaded = coordinator.getUploaded();
|
|
||||||
downloaded = coordinator.getDownloaded();
|
|
||||||
left = coordinator.getLeft(); // -1 in magnet mode
|
|
||||||
|
|
||||||
// First time we got a complete download?
|
// First time we got a complete download?
|
||||||
String event;
|
String event;
|
||||||
@ -303,7 +383,7 @@ public class TrackerClient extends I2PAppThread
|
|||||||
// FIXME if id == us || dest == us continue;
|
// FIXME if id == us || dest == us continue;
|
||||||
// only delay if we actually make an attempt to add peer
|
// only delay if we actually make an attempt to add peer
|
||||||
if(coordinator.addPeer(cur) && it.hasNext()) {
|
if(coordinator.addPeer(cur) && it.hasNext()) {
|
||||||
int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN;
|
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
|
||||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,7 +434,7 @@ public class TrackerClient extends I2PAppThread
|
|||||||
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
|
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
|
||||||
Peer cur = it.next();
|
Peer cur = it.next();
|
||||||
if (coordinator.addPeer(cur) && it.hasNext()) {
|
if (coordinator.addPeer(cur) && it.hasNext()) {
|
||||||
int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN;
|
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
|
||||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,7 +470,7 @@ public class TrackerClient extends I2PAppThread
|
|||||||
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
|
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
|
||||||
Peer cur = it.next();
|
Peer cur = it.next();
|
||||||
if (coordinator.addPeer(cur) && it.hasNext()) {
|
if (coordinator.addPeer(cur) && it.hasNext()) {
|
||||||
int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN;
|
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
|
||||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,8 +480,36 @@ public class TrackerClient extends I2PAppThread
|
|||||||
|
|
||||||
// we could try and total the unique peers but that's too hard for now
|
// we could try and total the unique peers but that's too hard for now
|
||||||
snark.setTrackerSeenPeers(maxSeenPeers);
|
snark.setTrackerSeenPeers(maxSeenPeers);
|
||||||
|
|
||||||
|
if (stop)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!runStarted)
|
if (!runStarted)
|
||||||
_util.debug(" Retrying in one minute...", Snark.DEBUG);
|
_util.debug(" Retrying in one minute...", Snark.DEBUG);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Sleep some minutes...
|
||||||
|
// Sleep the minimum interval for all the trackers, but 60s minimum
|
||||||
|
int delay;
|
||||||
|
int random = r.nextInt(120*1000);
|
||||||
|
if (completed && runStarted)
|
||||||
|
delay = 3*SLEEP*60*1000 + random;
|
||||||
|
else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
|
||||||
|
delay = INITIAL_SLEEP;
|
||||||
|
else
|
||||||
|
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
|
||||||
|
delay = SLEEP*60*1000 + random;
|
||||||
|
|
||||||
|
if (delay > 20*1000) {
|
||||||
|
// put ourselves on SimpleTimer2
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Requeueing in " + DataHelper.formatDuration(delay) + ": " + Thread.currentThread().getName());
|
||||||
|
queueLoop(delay);
|
||||||
|
return;
|
||||||
|
} else if (delay > 0) {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
}
|
||||||
|
} catch(InterruptedException interrupt) {}
|
||||||
} // *** end of while loop
|
} // *** end of while loop
|
||||||
} // try
|
} // try
|
||||||
catch (Throwable t)
|
catch (Throwable t)
|
||||||
@ -410,26 +518,61 @@ public class TrackerClient extends I2PAppThread
|
|||||||
if (t instanceof OutOfMemoryError)
|
if (t instanceof OutOfMemoryError)
|
||||||
throw (OutOfMemoryError)t;
|
throw (OutOfMemoryError)t;
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
{
|
|
||||||
|
/**
|
||||||
|
* Creates a thread for each tracker in parallel if tunnel is still open
|
||||||
|
* @since 0.9.1
|
||||||
|
*/
|
||||||
|
private void unannounce() {
|
||||||
// Local DHT tracker unannounce
|
// Local DHT tracker unannounce
|
||||||
if (_util.getDHT() != null)
|
if (_util.getDHT() != null)
|
||||||
_util.getDHT().unannounce(snark.getInfoHash());
|
_util.getDHT().unannounce(snark.getInfoHash());
|
||||||
|
int i = 0;
|
||||||
|
for (Tracker tr : trackers) {
|
||||||
|
if (_util.connected() &&
|
||||||
|
tr.started && (!tr.stop) && tr.trackerProblems == null) {
|
||||||
|
try {
|
||||||
|
(new I2PAppThread(new Unannouncer(tr), _threadName + " Unannounce " + (++i), true)).start();
|
||||||
|
} catch (OutOfMemoryError oom) {
|
||||||
|
// probably ran out of threads, ignore
|
||||||
|
tr.reset();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tr.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send "stopped" to a single tracker
|
||||||
|
* @since 0.9.1
|
||||||
|
*/
|
||||||
|
private class Unannouncer implements Runnable {
|
||||||
|
private final Tracker tr;
|
||||||
|
|
||||||
|
public Unannouncer(Tracker tr) {
|
||||||
|
this.tr = tr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Running unannounce " + _threadName + " to " + tr.announce);
|
||||||
|
long uploaded = coordinator.getUploaded();
|
||||||
|
long downloaded = coordinator.getDownloaded();
|
||||||
|
long left = coordinator.getLeft();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// try to contact everybody we can
|
|
||||||
// Don't try to restart I2CP connection just to say goodbye
|
// Don't try to restart I2CP connection just to say goodbye
|
||||||
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
|
if (_util.connected()) {
|
||||||
if (!_util.connected()) return;
|
|
||||||
Tracker tr = (Tracker)iter.next();
|
|
||||||
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
|
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
|
||||||
doRequest(tr, infoHash, peerID, uploaded,
|
doRequest(tr, infoHash, peerID, uploaded,
|
||||||
downloaded, left, STOPPED_EVENT);
|
downloaded, left, STOPPED_EVENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(IOException ioe) { /* ignored */ }
|
catch(IOException ioe) { /* ignored */ }
|
||||||
|
tr.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrackerInfo doRequest(Tracker tr, String infoHash,
|
private TrackerInfo doRequest(Tracker tr, String infoHash,
|
||||||
@ -467,7 +610,8 @@ public class TrackerClient extends I2PAppThread
|
|||||||
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
|
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
|
||||||
|
|
||||||
tr.lastRequestTime = System.currentTimeMillis();
|
tr.lastRequestTime = System.currentTimeMillis();
|
||||||
File fetched = _util.get(s);
|
// Don't wait for a response to stopped.
|
||||||
|
File fetched = _util.get(s, true, event.equals(STOPPED_EVENT) ? -1 : 0);
|
||||||
if (fetched == null) {
|
if (fetched == null) {
|
||||||
throw new IOException("Error fetching " + s);
|
throw new IOException("Error fetching " + s);
|
||||||
}
|
}
|
||||||
@ -556,6 +700,13 @@ public class TrackerClient extends I2PAppThread
|
|||||||
announce = a;
|
announce = a;
|
||||||
isPrimary = p;
|
isPrimary = p;
|
||||||
interval = INITIAL_SLEEP;
|
interval = INITIAL_SLEEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call before restarting
|
||||||
|
* @since 0.9.1
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
lastRequestTime = 0;
|
lastRequestTime = 0;
|
||||||
trackerProblems = null;
|
trackerProblems = null;
|
||||||
stop = false;
|
stop = false;
|
||||||
|
@ -743,8 +743,10 @@ public class I2PSnarkServlet extends DefaultServlet {
|
|||||||
List snarks = getSortedSnarks(req);
|
List snarks = getSortedSnarks(req);
|
||||||
for (int i = 0; i < snarks.size(); i++) {
|
for (int i = 0; i < snarks.size(); i++) {
|
||||||
Snark snark = (Snark)snarks.get(i);
|
Snark snark = (Snark)snarks.get(i);
|
||||||
if (!snark.isStopped())
|
if (!snark.isStopped()) {
|
||||||
_manager.stopTorrent(snark, false);
|
_manager.stopTorrent(snark, false);
|
||||||
|
try { Thread.sleep(50); } catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (_manager.util().connected()) {
|
if (_manager.util().connected()) {
|
||||||
// Give the stopped announces time to get out
|
// Give the stopped announces time to get out
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
- Sort magnets and downloads first
|
- Sort magnets and downloads first
|
||||||
- Fix sorting problem when torrent dir is a symlink
|
- Fix sorting problem when torrent dir is a symlink
|
||||||
- Reduce max file idle time
|
- Reduce max file idle time
|
||||||
|
- Reduce TrackerClient threads
|
||||||
|
- Reduce delay between peer adds for faster startup
|
||||||
|
- Thread the announces and reduce timeout when stopping
|
||||||
* NativeBigInteger: Workaround for Raspberry Pi to load the correct lib
|
* NativeBigInteger: Workaround for Raspberry Pi to load the correct lib
|
||||||
|
|
||||||
2012-06-08 zzz
|
2012-06-08 zzz
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 12;
|
public final static long BUILD = 13;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user