diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigAdvancedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigAdvancedHandler.java index c5c7cc9216..8539d1ca64 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigAdvancedHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/ConfigAdvancedHandler.java @@ -109,9 +109,8 @@ public class ConfigAdvancedHandler extends FormHandler { FloodfillNetworkDatabaseFacade fndf = (FloodfillNetworkDatabaseFacade) _context.netDb(); boolean wasFF = fndf.floodfillEnabled(); boolean isFF = _ff.equals("true"); + // this will rebuild the RI, log in the event log, etc. fndf.setFloodfillEnabled(isFF); - if (wasFF != isFF) - _context.router().rebuildRouterInfo(); } if (saved) addFormNotice(_t("Configuration saved successfully")); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java index 39aec4042f..3de4828cfa 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java @@ -31,6 +31,7 @@ class FloodfillMonitorJob extends JobImpl { private final Log _log; private final FloodfillNetworkDatabaseFacade _facade; private long _lastChanged; + private boolean _deferredFlood; private static final int REQUEUE_DELAY = 60*60*1000; private static final long MIN_UPTIME = 2*60*60*1000; @@ -48,10 +49,10 @@ class FloodfillMonitorJob extends JobImpl { public String getName() { return "Monitor the floodfill pool"; } - public void runJob() { + public synchronized void runJob() { boolean wasFF = _facade.floodfillEnabled(); boolean ff = shouldBeFloodfill(); - _facade.setFloodfillEnabled(ff); + _facade.setFloodfillEnabledFromMonitor(ff); if (ff != wasFF) { if (ff) { getContext().router().eventLog().addEvent(EventLog.BECAME_FLOODFILL); @@ -60,12 +61,15 @@ class FloodfillMonitorJob extends JobImpl { } getContext().router().rebuildRouterInfo(true); Job routerInfoFlood = new FloodfillRouterInfoFloodJob(getContext(), _facade); - if(getContext().router().getUptime() < 5*60*1000) { - // Needed to prevent race if router.floodfillParticipant=true (not auto) - routerInfoFlood.getTiming().setStartAfter(getContext().clock().now() + 5*60*1000); - getContext().jobQueue().addJob(routerInfoFlood); - if(_log.shouldLog(Log.DEBUG)) { - _log.logAlways(Log.DEBUG, "Deferring our FloodfillRouterInfoFloodJob run because of low uptime."); + if (getContext().router().getUptime() < 5*60*1000) { + if (!_deferredFlood) { + // Needed to prevent race if router.floodfillParticipant=true (not auto) + // Don't queue multiples + _deferredFlood = true; + routerInfoFlood.getTiming().setStartAfter(getContext().clock().now() + 5*60*1000); + getContext().jobQueue().addJob(routerInfoFlood); + if (_log.shouldLog(Log.DEBUG)) + _log.logAlways(Log.DEBUG, "Deferring our FloodfillRouterInfoFloodJob run because of low uptime."); } } else { routerInfoFlood.runJob(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java index 89c00aa990..d606e42a55 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -33,6 +33,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad private final Set _verifiesInProgress; private FloodThrottler _floodThrottler; private LookupThrottler _lookupThrottler; + private final Job _ffMonitor; /** * This is the flood redundancy. Entries are @@ -68,12 +69,13 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad _context.statManager().createRateStat("netDb.republishQuantity", "How many peers do we need to send a found leaseSet to?", "NetworkDatabase", new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); // for ISJ _context.statManager().createRateStat("netDb.RILookupDirect", "Was an iterative RI lookup sent directly?", "NetworkDatabase", new long[] { 60*60*1000 }); + _ffMonitor = new FloodfillMonitorJob(_context, this); } @Override public synchronized void startup() { super.startup(); - _context.jobQueue().addJob(new FloodfillMonitorJob(_context, this)); + _context.jobQueue().addJob(_ffMonitor); _lookupThrottler = new LookupThrottler(); // refresh old routers @@ -114,6 +116,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad } catch (InterruptedException ie) {} } } + _context.jobQueue().removeJob(_ffMonitor); super.shutdown(); } @@ -278,7 +281,24 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad @Override protected PeerSelector createPeerSelector() { return new FloodfillPeerSelector(_context); } + /** + * Public, called from console. This wakes up the floodfill monitor, + * which will rebuild the RI and log in the event log, + * and call setFloodfillEnabledFromMonitor which really sets it. + */ public synchronized void setFloodfillEnabled(boolean yes) { + if (yes != _floodfillEnabled) { + _context.jobQueue().removeJob(_ffMonitor); + _ffMonitor.getTiming().setStartAfter(_context.clock().now() + 1000); + _context.jobQueue().addJob(_ffMonitor); + } + } + + /** + * Package private, called from FloodfillMonitorJob. This does not wake up the floodfill monitor. + * @since 0.9.34 + */ + synchronized void setFloodfillEnabledFromMonitor(boolean yes) { _floodfillEnabled = yes; if (yes && _floodThrottler == null) { _floodThrottler = new FloodThrottler();