mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 23:29:52 +01:00
Start and stop plugins in parallel for faster startup and shutdown.
This commit is contained in:
@@ -7,11 +7,12 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
@@ -54,8 +55,8 @@ class PluginManagerImpl implements PluginManager {
|
|||||||
private final Poller poller;
|
private final Poller poller;
|
||||||
private final ConnectionDispatcher dispatcher;
|
private final ConnectionDispatcher dispatcher;
|
||||||
private final UiCallback uiCallback;
|
private final UiCallback uiCallback;
|
||||||
private final List<SimplexPlugin> simplexPlugins; // Locking: this
|
private final List<SimplexPlugin> simplexPlugins;
|
||||||
private final List<DuplexPlugin> duplexPlugins; // Locking: this
|
private final List<DuplexPlugin> duplexPlugins;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor,
|
PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor,
|
||||||
@@ -72,83 +73,36 @@ class PluginManagerImpl implements PluginManager {
|
|||||||
this.poller = poller;
|
this.poller = poller;
|
||||||
this.dispatcher = dispatcher;
|
this.dispatcher = dispatcher;
|
||||||
this.uiCallback = uiCallback;
|
this.uiCallback = uiCallback;
|
||||||
simplexPlugins = new ArrayList<SimplexPlugin>();
|
simplexPlugins = new CopyOnWriteArrayList<SimplexPlugin>();
|
||||||
duplexPlugins = new ArrayList<DuplexPlugin>();
|
duplexPlugins = new CopyOnWriteArrayList<DuplexPlugin>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized int start() {
|
public synchronized int start() {
|
||||||
Set<TransportId> ids = new HashSet<TransportId>();
|
|
||||||
// Instantiate and start the simplex plugins
|
// Instantiate and start the simplex plugins
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Starting simplex plugins");
|
if(LOG.isLoggable(INFO)) LOG.info("Starting simplex plugins");
|
||||||
for(SimplexPluginFactory factory : simplexPluginConfig.getFactories()) {
|
Collection<SimplexPluginFactory> sFactories =
|
||||||
TransportId id = factory.getId();
|
simplexPluginConfig.getFactories();
|
||||||
if(!ids.add(id)) {
|
final CountDownLatch sLatch = new CountDownLatch(sFactories.size());
|
||||||
if(LOG.isLoggable(WARNING))
|
for(SimplexPluginFactory factory : sFactories) {
|
||||||
LOG.warning("Duplicate transport ID: " + id);
|
pluginExecutor.execute(new SimplexPluginStarter(factory, sLatch));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SimplexCallback callback = new SimplexCallback(id);
|
|
||||||
SimplexPlugin plugin = factory.createPlugin(callback);
|
|
||||||
if(plugin == null) {
|
|
||||||
if(LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info(factory.getClass().getSimpleName()
|
|
||||||
+ " did not create a plugin");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
db.addTransport(id, plugin.getMaxLatency());
|
|
||||||
} catch(DbException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if(plugin.start()) {
|
|
||||||
simplexPlugins.add(plugin);
|
|
||||||
} else {
|
|
||||||
if(LOG.isLoggable(INFO))
|
|
||||||
LOG.info(plugin.getClass().getSimpleName()
|
|
||||||
+ " did not start");
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Instantiate and start the duplex plugins
|
// Instantiate and start the duplex plugins
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Starting duplex plugins");
|
if(LOG.isLoggable(INFO)) LOG.info("Starting duplex plugins");
|
||||||
for(DuplexPluginFactory factory : duplexPluginConfig.getFactories()) {
|
Collection<DuplexPluginFactory> dFactories =
|
||||||
TransportId id = factory.getId();
|
duplexPluginConfig.getFactories();
|
||||||
if(!ids.add(id)) {
|
final CountDownLatch dLatch = new CountDownLatch(dFactories.size());
|
||||||
if(LOG.isLoggable(WARNING))
|
for(DuplexPluginFactory factory : dFactories) {
|
||||||
LOG.warning("Duplicate transport ID: " + id);
|
pluginExecutor.execute(new DuplexPluginStarter(factory, dLatch));
|
||||||
continue;
|
}
|
||||||
}
|
// Wait for the plugins to start
|
||||||
DuplexCallback callback = new DuplexCallback(id);
|
try {
|
||||||
DuplexPlugin plugin = factory.createPlugin(callback);
|
sLatch.await();
|
||||||
if(plugin == null) {
|
dLatch.await();
|
||||||
if(LOG.isLoggable(INFO)) {
|
} catch(InterruptedException e) {
|
||||||
LOG.info(factory.getClass().getSimpleName()
|
if(LOG.isLoggable(WARNING))
|
||||||
+ " did not create a plugin");
|
LOG.warning("Interrupted while starting plugins");
|
||||||
}
|
Thread.currentThread().interrupt();
|
||||||
continue;
|
return 0;
|
||||||
}
|
|
||||||
try {
|
|
||||||
db.addTransport(id, plugin.getMaxLatency());
|
|
||||||
} catch(DbException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if(plugin.start()) {
|
|
||||||
duplexPlugins.add(plugin);
|
|
||||||
} else {
|
|
||||||
if(LOG.isLoggable(INFO))
|
|
||||||
LOG.info(plugin.getClass().getSimpleName()
|
|
||||||
+ " did not start");
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Start the poller
|
// Start the poller
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Starting poller");
|
if(LOG.isLoggable(INFO)) LOG.info("Starting poller");
|
||||||
@@ -157,51 +111,175 @@ class PluginManagerImpl implements PluginManager {
|
|||||||
plugins.addAll(duplexPlugins);
|
plugins.addAll(duplexPlugins);
|
||||||
poller.start(Collections.unmodifiableList(plugins));
|
poller.start(Collections.unmodifiableList(plugins));
|
||||||
// Return the number of plugins successfully started
|
// Return the number of plugins successfully started
|
||||||
return simplexPlugins.size() + duplexPlugins.size();
|
return plugins.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized int stop() {
|
public synchronized int stop() {
|
||||||
int stopped = 0;
|
|
||||||
// Stop the poller
|
// Stop the poller
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Stopping poller");
|
if(LOG.isLoggable(INFO)) LOG.info("Stopping poller");
|
||||||
poller.stop();
|
poller.stop();
|
||||||
|
final AtomicInteger stopped = new AtomicInteger(0);
|
||||||
|
int plugins = simplexPlugins.size() + duplexPlugins.size();
|
||||||
|
final CountDownLatch latch = new CountDownLatch(plugins);
|
||||||
// Stop the simplex plugins
|
// Stop the simplex plugins
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Stopping simplex plugins");
|
if(LOG.isLoggable(INFO)) LOG.info("Stopping simplex plugins");
|
||||||
for(SimplexPlugin plugin : simplexPlugins) {
|
for(SimplexPlugin plugin : simplexPlugins) {
|
||||||
try {
|
pluginExecutor.execute(new PluginStopper(plugin, latch, stopped));
|
||||||
plugin.stop();
|
|
||||||
stopped++;
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
simplexPlugins.clear();
|
|
||||||
// Stop the duplex plugins
|
// Stop the duplex plugins
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Stopping duplex plugins");
|
if(LOG.isLoggable(INFO)) LOG.info("Stopping duplex plugins");
|
||||||
for(DuplexPlugin plugin : duplexPlugins) {
|
for(DuplexPlugin plugin : duplexPlugins) {
|
||||||
try {
|
pluginExecutor.execute(new PluginStopper(plugin, latch, stopped));
|
||||||
plugin.stop();
|
|
||||||
stopped++;
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
simplexPlugins.clear();
|
||||||
duplexPlugins.clear();
|
duplexPlugins.clear();
|
||||||
|
// Wait for all the plugins to stop
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Interrupted while stopping plugins");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
// Shut down the executors
|
// Shut down the executors
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Stopping executors");
|
if(LOG.isLoggable(INFO)) LOG.info("Stopping executors");
|
||||||
pluginExecutor.shutdown();
|
pluginExecutor.shutdown();
|
||||||
androidExecutor.shutdown();
|
androidExecutor.shutdown();
|
||||||
// Return the number of plugins successfully stopped
|
// Return the number of plugins successfully stopped
|
||||||
return stopped;
|
return stopped.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Collection<DuplexPlugin> getInvitationPlugins() {
|
public Collection<DuplexPlugin> getInvitationPlugins() {
|
||||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||||
for(DuplexPlugin d : duplexPlugins)
|
for(DuplexPlugin d : duplexPlugins)
|
||||||
if(d.supportsInvitations()) supported.add(d);
|
if(d.supportsInvitations()) supported.add(d);
|
||||||
return Collections.unmodifiableList(supported);
|
return Collections.unmodifiableList(supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SimplexPluginStarter implements Runnable {
|
||||||
|
|
||||||
|
private final SimplexPluginFactory factory;
|
||||||
|
private final CountDownLatch latch;
|
||||||
|
|
||||||
|
private SimplexPluginStarter(SimplexPluginFactory factory,
|
||||||
|
CountDownLatch latch) {
|
||||||
|
this.factory = factory;
|
||||||
|
this.latch = latch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
TransportId id = factory.getId();
|
||||||
|
SimplexCallback callback = new SimplexCallback(id);
|
||||||
|
SimplexPlugin plugin = factory.createPlugin(callback);
|
||||||
|
if(plugin == null) {
|
||||||
|
if(LOG.isLoggable(INFO)) {
|
||||||
|
String name = factory.getClass().getSimpleName();
|
||||||
|
LOG.info(name + " did not create a plugin");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
db.addTransport(id, plugin.getMaxLatency());
|
||||||
|
} catch(DbException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(plugin.start()) {
|
||||||
|
simplexPlugins.add(plugin);
|
||||||
|
} else {
|
||||||
|
if(LOG.isLoggable(INFO)) {
|
||||||
|
String name = plugin.getClass().getSimpleName();
|
||||||
|
LOG.info(name + " did not start");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DuplexPluginStarter implements Runnable {
|
||||||
|
|
||||||
|
private final DuplexPluginFactory factory;
|
||||||
|
private final CountDownLatch latch;
|
||||||
|
|
||||||
|
private DuplexPluginStarter(DuplexPluginFactory factory,
|
||||||
|
CountDownLatch latch) {
|
||||||
|
this.factory = factory;
|
||||||
|
this.latch = latch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
TransportId id = factory.getId();
|
||||||
|
DuplexCallback callback = new DuplexCallback(id);
|
||||||
|
DuplexPlugin plugin = factory.createPlugin(callback);
|
||||||
|
if(plugin == null) {
|
||||||
|
if(LOG.isLoggable(INFO)) {
|
||||||
|
String name = factory.getClass().getSimpleName();
|
||||||
|
LOG.info(name + " did not create a plugin");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
db.addTransport(id, plugin.getMaxLatency());
|
||||||
|
} catch(DbException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(plugin.start()) {
|
||||||
|
duplexPlugins.add(plugin);
|
||||||
|
} else {
|
||||||
|
if(LOG.isLoggable(INFO)) {
|
||||||
|
String name = plugin.getClass().getSimpleName();
|
||||||
|
LOG.info(name + " did not start");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PluginStopper implements Runnable {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final CountDownLatch latch;
|
||||||
|
private final AtomicInteger stopped;
|
||||||
|
|
||||||
|
private PluginStopper(Plugin plugin, CountDownLatch latch,
|
||||||
|
AtomicInteger stopped) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.latch = latch;
|
||||||
|
this.stopped = stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
plugin.stop();
|
||||||
|
stopped.incrementAndGet();
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private abstract class PluginCallbackImpl implements PluginCallback {
|
private abstract class PluginCallbackImpl implements PluginCallback {
|
||||||
|
|
||||||
protected final TransportId id;
|
protected final TransportId id;
|
||||||
|
|||||||
Reference in New Issue
Block a user