* Reseeder: Get rid of static instance, root in netDB,

don't use system properties for status
This commit is contained in:
zzz
2012-03-22 19:47:44 +00:00
parent ca57b71266
commit adcd1e8d9a
8 changed files with 182 additions and 63 deletions

View File

@ -17,6 +17,7 @@ import net.i2p.data.DatabaseEntry;
import net.i2p.data.Hash;
import net.i2p.data.LeaseSet;
import net.i2p.data.RouterInfo;
import net.i2p.router.networkdb.reseed.ReseedChecker;
/**
* Defines the mechanism for interacting with I2P's network database
@ -73,4 +74,7 @@ public abstract class NetworkDatabaseFacade implements Service {
public Set<LeaseSet> getLeases() { return Collections.EMPTY_SET; }
/** public for NetDbRenderer in routerconsole */
public Set<RouterInfo> getRouters() { return Collections.EMPTY_SET; }
/** @since 0.9 */
public ReseedChecker reseedChecker() { return null; };
}

View File

@ -42,6 +42,7 @@ import net.i2p.router.TunnelPoolSettings;
import net.i2p.router.networkdb.DatabaseLookupMessageHandler;
import net.i2p.router.networkdb.DatabaseStoreMessageHandler;
import net.i2p.router.networkdb.PublishLocalRouterInfoJob;
import net.i2p.router.networkdb.reseed.ReseedChecker;
import net.i2p.router.peermanager.PeerProfile;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
@ -67,6 +68,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
private long _lastExploreNew;
protected final PeerSelector _peerSelector;
protected final RouterContext _context;
private final ReseedChecker _reseedChecker;
/**
* Map of Hash to RepublishLeaseSetJob for leases we'realready managing.
* This is added to when we create a new RepublishLeaseSetJob, and the values are
@ -146,6 +149,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
_publishingLeaseSets = new HashMap(8);
_activeRequests = new HashMap(8);
_enforceNetId = DEFAULT_ENFORCE_NETID;
_reseedChecker = new ReseedChecker(context);
context.statManager().createRateStat("netDb.lookupLeaseSetDeferred", "how many lookups are deferred for a single leaseSet lookup?", "NetworkDatabase", new long[] { 60*60*1000 });
context.statManager().createRateStat("netDb.exploreKeySet", "how many keys are queued for exploration?", "NetworkDatabase", new long[] { 60*60*1000 });
// following are for StoreJob
@ -167,6 +171,12 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
protected PeerSelector createPeerSelector() { return new PeerSelector(_context); }
public PeerSelector getPeerSelector() { return _peerSelector; }
/** @since 0.9 */
@Override
public ReseedChecker reseedChecker() {
return _reseedChecker;
}
KBucketSet getKBuckets() { return _kb; }
DataStore getDataStore() { return _ds; }

View File

@ -382,7 +382,7 @@ class PersistentDataStore extends TransientDataStore {
}
if (!_alreadyWarned) {
ReseedChecker.checkReseed(_context, routerCount);
_facade.reseedChecker().checkReseed(routerCount);
_alreadyWarned = true;
_initialized = true;
}

View File

@ -1,6 +1,7 @@
package net.i2p.router.networkdb.reseed;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
@ -19,29 +20,144 @@ import net.i2p.util.Log;
*/
public class ReseedChecker {
private final RouterContext _context;
private final Log _log;
private final AtomicBoolean _inProgress = new AtomicBoolean();
private String _lastStatus = "";
private String _lastError = "";
private static final int MINIMUM = 15;
public static void checkReseed(RouterContext context, int count) {
/**
* All reseeding must be done through this instance.
* Access through context.netDb().reseedChecker(), others should not instantiate
*
* @since 0.9
*/
public ReseedChecker(RouterContext context) {
_context = context;
_log = context.logManager().getLog(ReseedChecker.class);
}
/**
* Check if a reseed is needed, and start it
*
* @param count current number of known routers
* @return true if a reseed was started
*/
public boolean checkReseed(int count) {
if (count >= MINIMUM)
return;
return false;
if (_context.getBooleanProperty(Reseeder.PROP_DISABLE)) {
String s = "Only " + count + " peers remaining but reseed disabled by configuration";
_lastError = s;
_log.logAlways(Log.WARN, s);
return false;
}
// we check the i2p installation directory for a flag telling us not to reseed,
// but also check the home directory for that flag too, since new users installing i2p
// don't have an installation directory that they can put the flag in yet.
File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed");
File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p");
File noReseedFileAlt2 = new File(context.getConfigDir(), ".i2pnoreseed");
File noReseedFileAlt3 = new File(context.getConfigDir(), "noreseed.i2p");
Log _log = context.logManager().getLog(ReseedChecker.class);
File noReseedFileAlt2 = new File(_context.getConfigDir(), ".i2pnoreseed");
File noReseedFileAlt3 = new File(_context.getConfigDir(), "noreseed.i2p");
if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) {
if (count <= 1)
_log.logAlways(Log.INFO, "Downloading peer router information for a new I2P installation");
else
_log.logAlways(Log.WARN, "Very few known peers remaining - reseeding now");
Reseeder reseeder = new Reseeder(context);
reseeder.requestReseed();
return requestReseed();
} else {
_log.logAlways(Log.WARN, "Only " + count + " peers remaining but reseed disabled by config file");
String s = "Only " + count + " peers remaining but reseed disabled by config file";
_lastError = s;
_log.logAlways(Log.WARN, s);
return false;
}
}
/**
* Start a reseed
*
* @return true if a reseed was started, false if already in progress
* @since 0.9
*/
public boolean requestReseed() {
if (_inProgress.compareAndSet(false, true)) {
try {
Reseeder reseeder = new Reseeder(_context, this);
reseeder.requestReseed();
return true;
} catch (Throwable t) {
_log.error("Reseed failed to start", t);
done();
return false;
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Reseed already in prgress");
return false;
}
}
/**
* Is a reseed in progress?
*
* @since 0.9
*/
public boolean inProgress() {
return _inProgress.get();
}
/**
* The reseed is complete
*
* @since 0.9
*/
void done() {
_inProgress.set(false);
}
/**
* Status from current reseed attempt,
* probably empty if no reseed in progress.
*
* @return non-null, may be empty
* @since 0.9
*/
public String getStatus() {
return _lastStatus;
}
/**
* Status from current reseed attempt
*
* @param s non-null, may be empty
* @since 0.9
*/
void setStatus(String s) {
_lastStatus = s;
}
/**
* Error from last or current reseed attempt
*
* @return non-null, may be empty
* @since 0.9
*/
public String getError() {
return _lastError;
}
/**
* Status from last or current reseed attempt
*
* @param s non-null, may be empty
* @since 0.9
*/
void setError(String s) {
_lastError = s;
}
}

View File

@ -42,10 +42,9 @@ import net.i2p.util.Translate;
* the router log, and the wrapper log.
*/
public class Reseeder {
/** FIXME don't keep a static reference, store _isRunning some other way */
private static ReseedRunner _reseedRunner;
private final RouterContext _context;
private final Log _log;
private final ReseedChecker _checker;
// Reject unreasonably big files, because we download into a ByteArrayOutputStream.
private static final long MAX_RESEED_RESPONSE_SIZE = 2 * 1024 * 1024;
@ -81,11 +80,6 @@ public class Reseeder {
"https://75.145.125.59/netDb/" + "," +
"https://i2p.mooo.com/netDb/";
private static final String PROP_INPROGRESS = "net.i2p.router.web.ReseedHandler.reseedInProgress";
/** the console shows this message while reseedInProgress == false */
private static final String PROP_ERROR = "net.i2p.router.web.ReseedHandler.errorMessage";
/** the console shows this message while reseedInProgress == true */
private static final String PROP_STATUS = "net.i2p.router.web.ReseedHandler.statusMessage";
public static final String PROP_PROXY_HOST = "router.reseedProxyHost";
public static final String PROP_PROXY_PORT = "router.reseedProxyPort";
/** @since 0.8.2 */
@ -106,32 +100,27 @@ public class Reseeder {
public static final String PROP_SPROXY_USERNAME = "router.reseedSSLProxy.username";
public static final String PROP_SPROXY_PASSWORD = "router.reseedSSLProxy.password";
public static final String PROP_SPROXY_AUTH_ENABLE = "router.reseedSSLProxy.authEnable";
/** @since 0.9 */
public static final String PROP_DISABLE = "router.reseedDisable";
// from PersistentDataStore
private static final String ROUTERINFO_PREFIX = "routerInfo-";
private static final String ROUTERINFO_SUFFIX = ".dat";
public Reseeder(RouterContext ctx) {
Reseeder(RouterContext ctx, ReseedChecker rc) {
_context = ctx;
_log = ctx.logManager().getLog(Reseeder.class);
_checker = rc;
}
public void requestReseed() {
synchronized (Reseeder.class) {
if (_reseedRunner == null)
_reseedRunner = new ReseedRunner();
if (_reseedRunner.isRunning()) {
return;
} else {
// set to daemon so it doesn't hang a shutdown
Thread reseed = new I2PAppThread(_reseedRunner, "Reseed", true);
reseed.start();
}
}
void requestReseed() {
ReseedRunner reseedRunner = new ReseedRunner();
// set to daemon so it doesn't hang a shutdown
Thread reseed = new I2PAppThread(reseedRunner, "Reseed", true);
reseed.start();
}
public class ReseedRunner implements Runnable, EepGet.StatusListener {
private class ReseedRunner implements Runnable, EepGet.StatusListener {
private boolean _isRunning;
private String _proxyHost;
private int _proxyPort;
@ -143,20 +132,21 @@ public class Reseeder {
public ReseedRunner() {
}
public boolean isRunning() { return _isRunning; }
/*
* Do it.
* We update PROP_ERROR here.
*/
public void run() {
try {
run2();
} finally {
_checker.done();
}
}
private void run2() {
_isRunning = true;
System.clearProperty(PROP_ERROR);
System.setProperty(PROP_STATUS, _("Reseeding"));
System.setProperty(PROP_INPROGRESS, "true");
_attemptStarted = 0;
_gotDate = 0;
_sslState = null; // start fresh
_checker.setError("");
_checker.setStatus(_("Reseeding"));
if (_context.getBooleanProperty(PROP_PROXY_ENABLE)) {
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
@ -165,24 +155,22 @@ public class Reseeder {
int total = reseed(false);
if (total >= 50) {
System.out.println("Reseed complete, " + total + " received");
System.clearProperty(PROP_ERROR);
_checker.setError("");
} else if (total > 0) {
System.out.println("Reseed complete, only " + total + " received");
System.setProperty(PROP_ERROR, ngettext("Reseed fetched only 1 router.",
_checker.setError(ngettext("Reseed fetched only 1 router.",
"Reseed fetched only {0} routers.", total));
} else {
System.out.println("Reseed failed, check network connection");
System.out.println(
"Ensure that nothing blocks outbound HTTP, check the logs, " +
"and if nothing helps, read the FAQ about reseeding manually.");
System.setProperty(PROP_ERROR, _("Reseed failed.") + ' ' +
_checker.setError(_("Reseed failed.") + ' ' +
_("See {0} for help.",
"<a target=\"_top\" href=\"/configreseed\">" + _("reseed configuration page") + "</a>"));
}
System.setProperty(PROP_INPROGRESS, "false");
System.clearProperty(PROP_STATUS);
_sslState = null; // don't hold ref
_isRunning = false;
_checker.setStatus("");
}
// EepGet status listeners
@ -311,7 +299,7 @@ public class Reseeder {
* Jetty directory listings are not compatible, as they look like
* HREF="/full/path/to/routerInfo-...
*
* We update PROP_STATUS here.
* We update the status here.
*
* @param echoStatus apparently always false
* @return count of routerinfos successfully fetched
@ -320,7 +308,7 @@ public class Reseeder {
try {
// Don't use context clock as we may be adjusting the time
final long timeLimit = System.currentTimeMillis() + MAX_TIME_PER_HOST;
System.setProperty(PROP_STATUS, _("Reseeding: fetching seed URL."));
_checker.setStatus(_("Reseeding: fetching seed URL."));
System.err.println("Reseeding from " + seedURL);
URL dir = new URL(seedURL);
byte contentRaw[] = readURL(dir);
@ -377,7 +365,7 @@ public class Reseeder {
for (Iterator<String> iter = urlList.iterator();
iter.hasNext() && fetched < 200 && System.currentTimeMillis() < timeLimit; ) {
try {
System.setProperty(PROP_STATUS,
_checker.setStatus(
_("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors));
if (!fetchSeed(seedURL, iter.next()))