now allow restarting within the same jvm (loading all the config options again, rebinding sockets, etc - it does NOT fire up all the clientApp tasks though - those aren't part of the router)
This commit is contained in:
@ -89,6 +89,7 @@ class DummyClientManagerFacade extends ClientManagerFacade {
|
||||
public void startup() {}
|
||||
public void stopAcceptingClients() { }
|
||||
public void shutdown() {}
|
||||
public void restart() {}
|
||||
|
||||
public void messageDeliveryStatusUpdate(Destination fromDest, MessageId id, boolean delivered) {}
|
||||
|
||||
|
@ -30,5 +30,6 @@ public abstract class CommSystemFacade implements Service {
|
||||
class DummyCommSystemFacade extends CommSystemFacade {
|
||||
public void shutdown() {}
|
||||
public void startup() {}
|
||||
public void restart() {}
|
||||
public void processMessage(OutNetMessage msg) { }
|
||||
}
|
||||
|
@ -239,6 +239,16 @@ public class JobQueue {
|
||||
}
|
||||
|
||||
public void allowParallelOperation() { _allowParallelOperation = true; }
|
||||
|
||||
public void restart() {
|
||||
synchronized (_timedJobs) {
|
||||
_timedJobs.clear();
|
||||
}
|
||||
synchronized (_readyJobs) {
|
||||
_readyJobs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
_alive = false;
|
||||
StringBuffer buf = new StringBuffer(1024);
|
||||
@ -344,7 +354,10 @@ public class JobQueue {
|
||||
t.start();
|
||||
}
|
||||
} else if (_queueRunners.size() == numThreads) {
|
||||
// noop
|
||||
for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); ) {
|
||||
JobQueueRunner runner = (JobQueueRunner)iter.next();
|
||||
runner.startRunning();
|
||||
}
|
||||
} else { // numThreads < # runners, so shrink
|
||||
//for (int i = _queueRunners.size(); i > numThreads; i++) {
|
||||
// QueueRunner runner = (QueueRunner)_queueRunners.get(new Integer(i));
|
||||
|
@ -30,6 +30,7 @@ class JobQueueRunner implements Runnable {
|
||||
public Job getLastJob() { return _lastJob; }
|
||||
public int getRunnerId() { return _id; }
|
||||
public void stopRunning() { _keepRunning = false; }
|
||||
public void startRunning() { _keepRunning = true; }
|
||||
public void run() {
|
||||
long lastActive = _context.clock().now();
|
||||
long jobNum = 0;
|
||||
|
@ -58,6 +58,7 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
_context = ctx;
|
||||
}
|
||||
|
||||
public void restart() {}
|
||||
public void shutdown() {}
|
||||
public void startup() {
|
||||
RouterInfo info = _context.router().getRouterInfo();
|
||||
|
@ -30,6 +30,7 @@ public interface PeerManagerFacade extends Service {
|
||||
class DummyPeerManagerFacade implements PeerManagerFacade {
|
||||
public void shutdown() {}
|
||||
public void startup() {}
|
||||
public void restart() {}
|
||||
public void renderStatusHTML(OutputStream out) { }
|
||||
public List selectPeers(PeerSelectionCriteria criteria) { return null; }
|
||||
}
|
||||
|
@ -512,6 +512,49 @@ public class Router {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current config options (returning true if save was
|
||||
* successful, false otherwise)
|
||||
*
|
||||
*/
|
||||
public boolean saveConfig() {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(_configFilename);
|
||||
_config.store(fos, "I2P Router config");
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error saving the config to " + _configFilename, ioe);
|
||||
return false;
|
||||
} finally {
|
||||
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
_isAlive = false;
|
||||
|
||||
try { _context.commSystem().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the comm system", t); }
|
||||
try { _context.clientManager().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the client manager", t); }
|
||||
try { _context.tunnelManager().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the tunnel manager", t); }
|
||||
try { _context.peerManager().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the peer manager", t); }
|
||||
try { _context.netDb().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the networkDb", t); }
|
||||
|
||||
//try { _context.jobQueue().restart(); } catch (Throwable t) { _log.log(Log.CRIT, "Error restarting the job queue", t); }
|
||||
|
||||
_log.log(Log.CRIT, "Restart teardown complete... ");
|
||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
||||
|
||||
_log.log(Log.CRIT, "Restarting...");
|
||||
|
||||
_isAlive = true;
|
||||
_started = _context.clock().now();
|
||||
|
||||
_log.log(Log.CRIT, "Restart complete");
|
||||
}
|
||||
|
||||
private void dumpStats() {
|
||||
//_log.log(Log.CRIT, "Lifetime stats:\n\n" + StatsGenerator.generateStatsPage());
|
||||
}
|
||||
|
@ -31,5 +31,11 @@ public interface Service {
|
||||
*/
|
||||
public void shutdown();
|
||||
|
||||
/**
|
||||
* Perform a soft restart.
|
||||
*
|
||||
*/
|
||||
public void restart();
|
||||
|
||||
public void renderStatusHTML(OutputStream out) throws IOException;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import net.i2p.util.Log;
|
||||
public class SessionKeyPersistenceHelper implements Service {
|
||||
private Log _log;
|
||||
private RouterContext _context;
|
||||
private SessionKeyWriterJob _writerJob;
|
||||
private final static long PERSIST_DELAY = 3*60*1000;
|
||||
private final static String PROP_SESSION_KEY_FILE = "router.sessionKeys.location";
|
||||
private final static String DEFAULT_SESSION_KEY_FILE = "sessionKeys.dat";
|
||||
@ -25,12 +26,18 @@ public class SessionKeyPersistenceHelper implements Service {
|
||||
public SessionKeyPersistenceHelper(RouterContext context) {
|
||||
_context = context;
|
||||
_log = _context.logManager().getLog(SessionKeyPersistenceHelper.class);
|
||||
_writerJob = new SessionKeyWriterJob();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
writeState();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
writeState();
|
||||
startup();
|
||||
}
|
||||
|
||||
private String getKeyFile() {
|
||||
String val = _context.router().getConfigSetting(PROP_SESSION_KEY_FILE);
|
||||
if (val == null)
|
||||
@ -58,7 +65,7 @@ public class SessionKeyPersistenceHelper implements Service {
|
||||
if (fin != null) try { fin.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
_context.jobQueue().addJob(new SessionKeyWriterJob());
|
||||
_context.jobQueue().addJob(_writerJob);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,9 @@ public class StatisticsManager implements Service {
|
||||
}
|
||||
|
||||
public void shutdown() {}
|
||||
public void restart() {
|
||||
startup();
|
||||
}
|
||||
public void startup() {
|
||||
String val = _context.router().getConfigSetting(PROP_PUBLISH_RANKINGS);
|
||||
try {
|
||||
|
@ -37,6 +37,19 @@ public class AdminListener implements Runnable {
|
||||
_running = false;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
// this works by taking advantage of the auto-retry mechanism in the
|
||||
// startup() loop (which we reset to wait 1s). by failing the socket
|
||||
// (through close()) and nulling it, we will have to try to build a new
|
||||
// serverSocket (using the *new* _port)
|
||||
_nextFailDelay = 1000;
|
||||
ServerSocket s = _socket;
|
||||
try {
|
||||
_socket = null;
|
||||
s.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
public void setPort(int port) { _port = port; }
|
||||
public int getPort() { return _port; }
|
||||
|
||||
@ -58,7 +71,7 @@ public class AdminListener implements Runnable {
|
||||
_log.info("Starting up listening for connections on port " + _port);
|
||||
_socket = new ServerSocket(_port);
|
||||
curDelay = 0;
|
||||
while (_running) {
|
||||
while (_running && (_socket != null) ) {
|
||||
try {
|
||||
Socket socket = _socket.accept();
|
||||
_log.debug("Connection received");
|
||||
|
@ -30,6 +30,10 @@ public class AdminManager implements Service {
|
||||
}
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
startup();
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
int port = DEFAULT_ADMIN_PORT;
|
||||
String str = _context.router().getConfigSetting(PARAM_ADMIN_PORT);
|
||||
@ -46,11 +50,16 @@ public class AdminManager implements Service {
|
||||
}
|
||||
|
||||
private void startup(int port) {
|
||||
_listener = new AdminListener(_context, port);
|
||||
I2PThread t = new I2PThread(_listener);
|
||||
t.setName("Admin Listener:" + port);
|
||||
t.setDaemon(true);
|
||||
//t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.start();
|
||||
if (_listener == null) {
|
||||
_listener = new AdminListener(_context, port);
|
||||
I2PThread t = new I2PThread(_listener);
|
||||
t.setName("Admin Listener:" + port);
|
||||
t.setDaemon(true);
|
||||
//t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.start();
|
||||
} else {
|
||||
_listener.setPort(port);
|
||||
_listener.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,28 @@ public class ClientManager {
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
shutdown();
|
||||
|
||||
// to let the old listener die
|
||||
try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
|
||||
|
||||
int port = ClientManagerFacadeImpl.DEFAULT_PORT;
|
||||
String portStr = _context.router().getConfigSetting(ClientManagerFacadeImpl.PROP_CLIENT_PORT);
|
||||
if (portStr != null) {
|
||||
try {
|
||||
port = Integer.parseInt(portStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Error setting the port: " + portStr + " is not valid", nfe);
|
||||
}
|
||||
}
|
||||
_listener = new ClientListenerRunner(_context, this, port);
|
||||
Thread t = new I2PThread(_listener);
|
||||
t.setName("ClientListener:" + port);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
_log.info("Shutting down the ClientManager");
|
||||
_listener.stopListening();
|
||||
|
@ -61,6 +61,13 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade {
|
||||
_manager.shutdown();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
if (_manager != null)
|
||||
_manager.restart();
|
||||
else
|
||||
startup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that a particular client authorize the Leases contained in the
|
||||
* LeaseSet, after which the onCreateJob is queued up. If that doesn't occur
|
||||
|
@ -19,4 +19,5 @@ public interface DataStore {
|
||||
public void put(Hash key, DataStructure data);
|
||||
public DataStructure remove(Hash key);
|
||||
public Set getKeys();
|
||||
public void restart();
|
||||
}
|
||||
|
@ -180,6 +180,26 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
|
||||
_exploreKeys = null;
|
||||
_lastSent = null;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
_dbDir = _context.router().getConfigSetting(PROP_DB_DIR);
|
||||
if (_dbDir == null) {
|
||||
_log.info("No DB dir specified [" + PROP_DB_DIR + "], using [" + DEFAULT_DB_DIR + "]");
|
||||
_dbDir = DEFAULT_DB_DIR;
|
||||
}
|
||||
_ds.restart();
|
||||
synchronized (_explicitSendKeys) { _explicitSendKeys.clear(); }
|
||||
synchronized (_exploreKeys) { _exploreKeys.clear(); }
|
||||
synchronized (_passiveSendKeys) { _passiveSendKeys.clear(); }
|
||||
|
||||
_initialized = true;
|
||||
|
||||
RouterInfo ri = _context.router().getRouterInfo();
|
||||
publish(ri);
|
||||
}
|
||||
|
||||
String getDbDir() { return _dbDir; }
|
||||
|
||||
public void startup() {
|
||||
_log.info("Starting up the kademlia network database");
|
||||
RouterInfo ri = _context.router().getRouterInfo();
|
||||
|
@ -45,6 +45,10 @@ class PersistentDataStore extends TransientDataStore {
|
||||
_context.jobQueue().addJob(new ReadJob());
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
_dbDir = _facade.getDbDir();
|
||||
}
|
||||
|
||||
public DataStructure remove(Hash key) {
|
||||
_context.jobQueue().addJob(new RemoveJob(key));
|
||||
return super.remove(key);
|
||||
|
@ -36,6 +36,12 @@ class TransientDataStore implements DataStore {
|
||||
_log.info("Data Store initialized");
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
synchronized (_data) {
|
||||
_data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Set getKeys() {
|
||||
synchronized (_data) {
|
||||
return new HashSet(_data.keySet());
|
||||
|
@ -49,6 +49,12 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade {
|
||||
_manager.storeProfiles();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
_manager.storeProfiles();
|
||||
_persistenceHelper.setUs(_context.routerHash());
|
||||
_manager.loadProfiles();
|
||||
}
|
||||
|
||||
public List selectPeers(PeerSelectionCriteria criteria) {
|
||||
return new ArrayList(_manager.selectPeers(criteria));
|
||||
}
|
||||
|
@ -45,6 +45,13 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
_manager.stopListening();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
if (_manager == null)
|
||||
startup();
|
||||
else
|
||||
_manager.restart();
|
||||
}
|
||||
|
||||
public List getBids(OutNetMessage msg) {
|
||||
return _manager.getBids(msg);
|
||||
}
|
||||
|
@ -101,6 +101,12 @@ public class TransportManager implements TransportEventListener {
|
||||
_log.debug("Done start listening on transports");
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
stopListening();
|
||||
try { Thread.sleep(1*1000); } catch (InterruptedException ie) {}
|
||||
startListening();
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
for (int i = 0; i < _transports.size(); i++) {
|
||||
((Transport)_transports.get(i)).stopListening();
|
||||
|
@ -148,5 +148,10 @@ public class VMCommSystem extends CommSystemFacade {
|
||||
_commSystemFacades.put(_context.routerHash(), this);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
_commSystemFacades.remove(_context.routerHash());
|
||||
_commSystemFacades.put(_context.routerHash(), this);
|
||||
}
|
||||
|
||||
public void renderStatusHTML(OutputStream out) {}
|
||||
}
|
||||
|
@ -56,6 +56,10 @@ public class PoolingTunnelManagerFacade implements TunnelManagerFacade {
|
||||
_testManager = null;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
_pool.restart();
|
||||
}
|
||||
|
||||
/**
|
||||
* React to a request to join the specified tunnel.
|
||||
*
|
||||
@ -230,4 +234,5 @@ public class PoolingTunnelManagerFacade implements TunnelManagerFacade {
|
||||
if (_pool != null)
|
||||
_pool.renderStatusHTML(out);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -576,6 +576,22 @@ class TunnelPool {
|
||||
_context.jobQueue().addJob(new TunnelPoolExpirationJob(_context, this));
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
try {
|
||||
String str = _context.router().getConfigSetting(TUNNEL_CREATION_TIMEOUT_PARAM);
|
||||
_tunnelCreationTimeout = Long.parseLong(str);
|
||||
} catch (Throwable t) {
|
||||
_tunnelCreationTimeout = TUNNEL_CREATION_TIMEOUT_DEFAULT;
|
||||
}
|
||||
_targetClients = TARGET_CLIENTS_DEFAULT;
|
||||
try {
|
||||
String str = _context.router().getConfigSetting(TARGET_CLIENTS_PARAM);
|
||||
_targetClients = Integer.parseInt(str);
|
||||
} catch (Throwable t) {
|
||||
_targetClients = TARGET_CLIENTS_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("Shutting down tunnel pool");
|
||||
if (_persistenceHelper != null)
|
||||
|
Reference in New Issue
Block a user