diff --git a/briar-core/src/org/briarproject/plugins/PollerImpl.java b/briar-core/src/org/briarproject/plugins/PollerImpl.java index 9611499b6b3f74ac1ee521d0b5ac99e99bb37845..50e79b3b27f77349908628121cd73597a6aee637 100644 --- a/briar-core/src/org/briarproject/plugins/PollerImpl.java +++ b/briar-core/src/org/briarproject/plugins/PollerImpl.java @@ -1,11 +1,15 @@ package org.briarproject.plugins; +import org.briarproject.api.TransportId; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.plugins.Plugin; import org.briarproject.api.system.Timer; +import java.security.SecureRandom; +import java.util.Map; import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -20,14 +24,19 @@ class PollerImpl implements Poller { private final Executor ioExecutor; private final ConnectionRegistry connectionRegistry; + private final SecureRandom random; private final Timer timer; + private final Map<TransportId, PollTask> tasks; @Inject PollerImpl(@IoExecutor Executor ioExecutor, - ConnectionRegistry connectionRegistry, Timer timer) { + ConnectionRegistry connectionRegistry, SecureRandom random, + Timer timer) { this.ioExecutor = ioExecutor; this.connectionRegistry = connectionRegistry; + this.random = random; this.timer = timer; + tasks = new ConcurrentHashMap<TransportId, PollTask>(); } public void stop() { @@ -35,17 +44,28 @@ class PollerImpl implements Poller { } public void addPlugin(Plugin p) { - schedule(p, true); + // Randomise first polling interval + schedule(p, randomise(p.getPollingInterval()), false); } - private void schedule(Plugin plugin, boolean randomise) { - long interval = plugin.getPollingInterval(); - // Randomise intervals at startup to spread out connection attempts - if (randomise) interval = (long) (interval * Math.random()); - timer.schedule(new PollTask(plugin), interval); + public void pollNow(Plugin p) { + // Randomise next polling interval + schedule(p, 0, true); } - public void pollNow(final Plugin p) { + private int randomise(int interval) { + return (int) (interval * random.nextDouble()); + } + + private void schedule(Plugin p, int interval, boolean randomiseNext) { + // Replace any previously scheduled task for this plugin + PollTask task = new PollTask(p, randomiseNext); + PollTask replaced = tasks.put(p.getId(), task); + if (replaced != null) replaced.cancel(); + timer.schedule(task, interval); + } + + private void poll(final Plugin p) { ioExecutor.execute(new Runnable() { public void run() { if (LOG.isLoggable(INFO)) @@ -58,15 +78,20 @@ class PollerImpl implements Poller { private class PollTask extends TimerTask { private final Plugin plugin; + private final boolean randomiseNext; - private PollTask(Plugin plugin) { + private PollTask(Plugin plugin, boolean randomiseNext) { this.plugin = plugin; + this.randomiseNext = randomiseNext; } @Override public void run() { - pollNow(plugin); - schedule(plugin, false); + tasks.remove(plugin.getId()); + int interval = plugin.getPollingInterval(); + if (randomiseNext) interval = randomise(interval); + schedule(plugin, interval, false); + poll(plugin); } } }