ReadWriteLock in TunnelControlGroup (#815)

This commit is contained in:
str4d
2015-03-23 12:49:30 +00:00
parent 2fefe93922
commit 2d31f30a22

View File

@@ -11,11 +11,12 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue; import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.app.*; import net.i2p.app.*;
@@ -43,6 +44,7 @@ public class TunnelControllerGroup implements ClientApp {
static final String DEFAULT_CONFIG_FILE = "i2ptunnel.config"; static final String DEFAULT_CONFIG_FILE = "i2ptunnel.config";
private final List<TunnelController> _controllers; private final List<TunnelController> _controllers;
private final ReadWriteLock _controllersLock;
private final String _configFile; private final String _configFile;
private static final String REGISTERED_NAME = "i2ptunnel"; private static final String REGISTERED_NAME = "i2ptunnel";
@@ -105,6 +107,7 @@ public class TunnelControllerGroup implements ClientApp {
_mgr = mgr; _mgr = mgr;
_log = _context.logManager().getLog(TunnelControllerGroup.class); _log = _context.logManager().getLog(TunnelControllerGroup.class);
_controllers = new ArrayList<TunnelController>(); _controllers = new ArrayList<TunnelController>();
_controllersLock = new ReentrantReadWriteLock(true);
if (args == null || args.length <= 0) if (args == null || args.length <= 0)
_configFile = DEFAULT_CONFIG_FILE; _configFile = DEFAULT_CONFIG_FILE;
else if (args.length == 1) else if (args.length == 1)
@@ -243,14 +246,19 @@ public class TunnelControllerGroup implements ClientApp {
public synchronized void loadControllers(String configFile) { public synchronized void loadControllers(String configFile) {
changeState(STARTING); changeState(STARTING);
Properties cfg = loadConfig(configFile); Properties cfg = loadConfig(configFile);
int i = 0; int i = 0;
while (true) { _controllersLock.writeLock().lock();
String type = cfg.getProperty("tunnel." + i + ".type"); try {
if (type == null) while (true) {
break; String type = cfg.getProperty("tunnel." + i + ".type");
TunnelController controller = new TunnelController(cfg, "tunnel." + i + "."); if (type == null)
_controllers.add(controller); break;
i++; TunnelController controller = new TunnelController(cfg, "tunnel." + i + ".");
_controllers.add(controller);
i++;
}
} finally {
_controllersLock.writeLock().unlock();
} }
I2PAppThread startupThread = new I2PAppThread(new StartControllers(), "Startup tunnels"); I2PAppThread startupThread = new I2PAppThread(new StartControllers(), "Startup tunnels");
startupThread.start(); startupThread.start();
@@ -263,10 +271,15 @@ public class TunnelControllerGroup implements ClientApp {
private class StartControllers implements Runnable { private class StartControllers implements Runnable {
public void run() { public void run() {
synchronized(TunnelControllerGroup.this) { synchronized(TunnelControllerGroup.this) {
for (int i = 0; i < _controllers.size(); i++) { _controllersLock.readLock().lock();
TunnelController controller = _controllers.get(i); try {
if (controller.getStartOnLoad()) for (int i = 0; i < _controllers.size(); i++) {
controller.startTunnel(); TunnelController controller = _controllers.get(i);
if (controller.getStartOnLoad())
controller.startTunnel();
}
} finally {
_controllersLock.readLock().unlock();
} }
} }
} }
@@ -289,19 +302,31 @@ public class TunnelControllerGroup implements ClientApp {
* *
*/ */
public synchronized void unloadControllers() { public synchronized void unloadControllers() {
destroyAllControllers(); _controllersLock.writeLock().lock();
_controllers.clear(); try {
destroyAllControllers();
_controllers.clear();
} finally {
_controllersLock.writeLock().unlock();
}
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("All controllers stopped and unloaded"); _log.info("All controllers stopped and unloaded");
} }
/** /**
* Add the given tunnel to the set of known controllers (but dont add it to * Add the given tunnel to the set of known controllers (but dont add it to
* a config file or start it or anything) * a config file or start it or anything)
* *
*/ */
public synchronized void addController(TunnelController controller) { _controllers.add(controller); } public synchronized void addController(TunnelController controller) {
_controllersLock.writeLock().lock();
try {
_controllers.add(controller);
} finally {
_controllersLock.writeLock().unlock();
}
}
/** /**
* Stop and remove the given tunnel * Stop and remove the given tunnel
* *
@@ -311,7 +336,12 @@ public class TunnelControllerGroup implements ClientApp {
if (controller == null) return new ArrayList<String>(); if (controller == null) return new ArrayList<String>();
controller.stopTunnel(); controller.stopTunnel();
List<String> msgs = controller.clearMessages(); List<String> msgs = controller.clearMessages();
_controllers.remove(controller); _controllersLock.writeLock().lock();
try {
_controllers.remove(controller);
} finally {
_controllersLock.writeLock().unlock();
}
msgs.add("Tunnel " + controller.getName() + " removed"); msgs.add("Tunnel " + controller.getName() + " removed");
return msgs; return msgs;
} }
@@ -323,13 +353,18 @@ public class TunnelControllerGroup implements ClientApp {
*/ */
public synchronized List<String> stopAllControllers() { public synchronized List<String> stopAllControllers() {
List<String> msgs = new ArrayList<String>(); List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) { _controllersLock.readLock().lock();
TunnelController controller = _controllers.get(i); try {
controller.stopTunnel(); for (int i = 0; i < _controllers.size(); i++) {
msgs.addAll(controller.clearMessages()); TunnelController controller = _controllers.get(i);
controller.stopTunnel();
msgs.addAll(controller.clearMessages());
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers stopped");
} finally {
_controllersLock.readLock().unlock();
} }
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers stopped");
return msgs; return msgs;
} }
@@ -355,14 +390,19 @@ public class TunnelControllerGroup implements ClientApp {
*/ */
public synchronized List<String> startAllControllers() { public synchronized List<String> startAllControllers() {
List<String> msgs = new ArrayList<String>(); List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) { _controllersLock.readLock().lock();
TunnelController controller = _controllers.get(i); try {
controller.startTunnelBackground(); for (int i = 0; i < _controllers.size(); i++) {
msgs.addAll(controller.clearMessages()); TunnelController controller = _controllers.get(i);
} controller.startTunnelBackground();
msgs.addAll(controller.clearMessages());
}
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers started"); _log.info(_controllers.size() + " controllers started");
} finally {
_controllersLock.readLock().unlock();
}
return msgs; return msgs;
} }
@@ -373,13 +413,18 @@ public class TunnelControllerGroup implements ClientApp {
*/ */
public synchronized List<String> restartAllControllers() { public synchronized List<String> restartAllControllers() {
List<String> msgs = new ArrayList<String>(); List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) { _controllersLock.readLock().lock();
TunnelController controller = _controllers.get(i); try {
controller.restartTunnel(); for (int i = 0; i < _controllers.size(); i++) {
msgs.addAll(controller.clearMessages()); TunnelController controller = _controllers.get(i);
controller.restartTunnel();
msgs.addAll(controller.clearMessages());
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers restarted");
} finally {
_controllersLock.readLock().unlock();
} }
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers restarted");
return msgs; return msgs;
} }
@@ -388,11 +433,16 @@ public class TunnelControllerGroup implements ClientApp {
* *
* @return list of messages the tunnels have generated * @return list of messages the tunnels have generated
*/ */
public synchronized List<String> clearAllMessages() { public List<String> clearAllMessages() {
List<String> msgs = new ArrayList<String>(); List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) { _controllersLock.readLock().lock();
TunnelController controller = _controllers.get(i); try {
msgs.addAll(controller.clearMessages()); for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
msgs.addAll(controller.clearMessages());
}
} finally {
_controllersLock.readLock().unlock();
} }
return msgs; return msgs;
} }
@@ -419,10 +469,15 @@ public class TunnelControllerGroup implements ClientApp {
parent.mkdirs(); parent.mkdirs();
Properties map = new OrderedProperties(); Properties map = new OrderedProperties();
for (int i = 0; i < _controllers.size(); i++) { _controllersLock.readLock().lock();
TunnelController controller = _controllers.get(i); try {
Properties cur = controller.getConfig("tunnel." + i + "."); for (int i = 0; i < _controllers.size(); i++) {
map.putAll(cur); TunnelController controller = _controllers.get(i);
Properties cur = controller.getConfig("tunnel." + i + ".");
map.putAll(cur);
}
} finally {
_controllersLock.readLock().unlock();
} }
DataHelper.storeProps(map, cfgFile); DataHelper.storeProps(map, cfgFile);
@@ -460,8 +515,13 @@ public class TunnelControllerGroup implements ClientApp {
* *
* @return list of TunnelController objects * @return list of TunnelController objects
*/ */
public synchronized List<TunnelController> getControllers() { public List<TunnelController> getControllers() {
return new ArrayList<TunnelController>(_controllers); _controllersLock.readLock().lock();
try {
return new ArrayList<TunnelController>(_controllers);
} finally {
_controllersLock.readLock().unlock();
}
} }