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:
jrandom
2004-07-31 02:21:46 +00:00
committed by zzz
parent bc2774bde4
commit a6993fa489
24 changed files with 215 additions and 11 deletions

View File

@ -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) {}

View File

@ -30,5 +30,6 @@ public abstract class CommSystemFacade implements Service {
class DummyCommSystemFacade extends CommSystemFacade {
public void shutdown() {}
public void startup() {}
public void processMessage(OutNetMessage msg) { }
public void restart() {}
public void processMessage(OutNetMessage msg) { }
}

View File

@ -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));

View File

@ -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;

View File

@ -57,7 +57,8 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
_routers = new HashMap();
_context = ctx;
}
public void restart() {}
public void shutdown() {}
public void startup() {
RouterInfo info = _context.router().getRouterInfo();

View File

@ -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; }
}

View File

@ -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());
}

View File

@ -31,5 +31,11 @@ public interface Service {
*/
public void shutdown();
/**
* Perform a soft restart.
*
*/
public void restart();
public void renderStatusHTML(OutputStream out) throws IOException;
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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");

View File

@ -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();
}
}
}

View File

@ -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();

View File

@ -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

View File

@ -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();
}

View File

@ -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();

View File

@ -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);

View File

@ -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());

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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) {}
}

View File

@ -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);
}
}

View File

@ -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)