* Router:

- Remove global lock on accessing config
      - Add global lock on reading/writing config file
This commit is contained in:
zzz
2010-11-24 16:40:13 +00:00
parent a8b602bc54
commit 8228365d4b

View File

@ -19,10 +19,12 @@ import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.CoreVersion;
import net.i2p.crypto.DHSessionKeyBuilder;
@ -57,7 +59,7 @@ import net.i2p.util.SimpleTimer;
public class Router {
private Log _log;
private RouterContext _context;
private final Properties _config;
private final Map<String, String> _config;
/** full path */
private String _configFilename;
private RouterInfo _routerInfo;
@ -120,7 +122,7 @@ public class Router {
public Router(String configFilename) { this(configFilename, null); }
public Router(String configFilename, Properties envProps) {
_gracefulExitCode = -1;
_config = new Properties();
_config = new ConcurrentHashMap();
if (configFilename == null) {
if (envProps != null) {
@ -168,15 +170,9 @@ public class Router {
readConfig();
if (envProps == null) {
envProps = _config;
} else {
for (Iterator iter = _config.keySet().iterator(); iter.hasNext(); ) {
String k = (String)iter.next();
String v = _config.getProperty(k);
envProps.setProperty(k, v);
}
}
if (envProps == null)
envProps = new Properties();
envProps.putAll(_config);
// This doesn't work, guess it has to be in the static block above?
// if (Boolean.valueOf(envProps.getProperty("router.disableIPv6")).booleanValue())
@ -203,12 +199,12 @@ public class Router {
System.exit(-1);
}
if (_config.getProperty("router.firstVersion") == null) {
if (_config.get("router.firstVersion") == null) {
// These may be useful someday. First added in 0.8.2
_config.setProperty("router.firstVersion", RouterVersion.VERSION);
_config.put("router.firstVersion", RouterVersion.VERSION);
String now = Long.toString(System.currentTimeMillis());
_config.setProperty("router.firstInstalled", now);
_config.setProperty("router.updateLastInstalled", now);
_config.put("router.firstInstalled", now);
_config.put("router.updateLastInstalled", now);
saveConfig();
}
@ -285,30 +281,20 @@ public class Router {
public void setConfigFilename(String filename) { _configFilename = filename; }
public String getConfigSetting(String name) {
synchronized (_config) {
return _config.getProperty(name);
}
return _config.get(name);
}
public void setConfigSetting(String name, String value) {
synchronized (_config) {
_config.setProperty(name, value);
}
_config.put(name, value);
}
public void removeConfigSetting(String name) {
synchronized (_config) {
_config.remove(name);
}
}
public Set getConfigSettings() {
synchronized (_config) {
return new HashSet(_config.keySet());
}
}
public Properties getConfigMap() {
Properties rv = new Properties();
synchronized (_config) {
rv.putAll(_config);
}
return rv;
}
@ -377,14 +363,19 @@ public class Router {
_context.jobQueue().addJob(new StartupJob(_context));
}
public void readConfig() {
/**
* This updates the config with all settings found in the file.
* It does not clear the config first, so settings not found in
* the file will remain in the config.
*
* This is synchronized with saveConfig()
*/
public synchronized void readConfig() {
String f = getConfigFilename();
Properties config = getConfig(_context, f);
for (Iterator iter = config.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
String val = config.getProperty(name);
setConfigSetting(name, val);
}
// to avoid compiler errror
Map foo = _config;
foo.putAll(config);
}
/** this does not use ctx.getConfigDir(), must provide a full path in filename */
@ -988,7 +979,7 @@ public class Router {
*/
public void shutdownGracefully(int exitCode) {
_gracefulExitCode = exitCode;
_config.setProperty(PROP_SHUTDOWN_IN_PROGRESS, "true");
_config.put(PROP_SHUTDOWN_IN_PROGRESS, "true");
synchronized (_gracefulShutdownDetector) {
_gracefulShutdownDetector.notifyAll();
}
@ -1010,7 +1001,7 @@ public class Router {
*/
public int scheduledGracefulExitCode() { return _gracefulExitCode; }
public boolean gracefulShutdownInProgress() {
return (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
return (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS));
}
/** How long until the graceful shutdown will kill us? */
public long getShutdownTimeRemaining() {
@ -1033,7 +1024,7 @@ public class Router {
private class GracefulShutdown implements Runnable {
public void run() {
while (true) {
boolean shutdown = (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
boolean shutdown = (null != _config.get(PROP_SHUTDOWN_IN_PROGRESS));
if (shutdown) {
if (_gracefulExitCode == EXIT_HARD || _gracefulExitCode == EXIT_HARD_RESTART ||
_context.tunnelManager().getParticipatingCount() <= 0) {
@ -1077,19 +1068,18 @@ public class Router {
* this does escape the \r or \n that are unescaped in DataHelper.loadProps().
* Note that the escaping of \r or \n was probably a mistake and should be taken out.
*
* FIXME Synchronize!!
* Synchronized with file read in getConfig()
*/
public boolean saveConfig() {
public synchronized boolean saveConfig() {
FileOutputStream fos = null;
try {
fos = new SecureFileOutputStream(_configFilename);
StringBuilder buf = new StringBuilder(8*1024);
buf.append("# NOTE: This I2P config file must use UTF-8 encoding\n");
synchronized (_config) {
TreeSet ordered = new TreeSet(_config.keySet());
for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
String key = (String)iter.next();
String val = _config.getProperty(key);
String val = _config.get(key);
// Escape line breaks before saving.
// Remember: "\" needs escaping both for regex and string.
// NOOO - see comments in DataHelper
@ -1097,7 +1087,6 @@ public class Router {
//val = val.replaceAll("\\n","\\\\n");
buf.append(key).append('=').append(val).append('\n');
}
}
fos.write(buf.toString().getBytes("UTF-8"));
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
@ -1193,7 +1182,7 @@ public class Router {
}
if (ok) {
// This may be useful someday. First added in 0.8.2
_config.setProperty("router.updateLastInstalled", "" + System.currentTimeMillis());
_config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
saveConfig();
boolean deleted = updateFile.delete();
if (!deleted) {