diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index b3cc3643b029881c435b6239de036407b15525c9..d3f2986e8587d6fa8b2bd02bf34bb15730fe226a 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -17,6 +17,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import net.i2p.data.Hash; import net.i2p.data.router.RouterInfo; @@ -43,6 +44,9 @@ class PeerManager { private final Map<Character, Set<Hash>> _peersByCapability; /** value strings are lower case */ private final Map<Hash, String> _capabilitiesByPeer; + private final AtomicBoolean _storeLock = new AtomicBoolean(); + private volatile long _lastStore; + private static final long REORGANIZE_TIME = 45*1000; private static final long REORGANIZE_TIME_MEDIUM = 123*1000; /** @@ -52,6 +56,7 @@ class PeerManager { * Rate contained in the profile, as the Rates must be coalesced. */ private static final long REORGANIZE_TIME_LONG = 351*1000; + private static final long STORE_TIME = 19*60*60*1000; public static final String TRACKED_CAPS = "" + FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL + @@ -97,11 +102,13 @@ class PeerManager { } /** + * Reorganize the profiles. Also periodically store them. + * * This takes too long to run on the SimpleTimer2 queue * @since 0.9.10 */ private class ReorgThread extends I2PThread { - private SimpleTimer2.TimedEvent _event; + private final SimpleTimer2.TimedEvent _event; public ReorgThread(SimpleTimer2.TimedEvent event) { super("PeerManager Reorg"); @@ -117,6 +124,18 @@ class PeerManager { _log.log(Log.CRIT, "Error evaluating profiles", t); } long orgtime = System.currentTimeMillis() - start; + if (_lastStore == 0) { + _lastStore = start; + } else if (start - _lastStore > STORE_TIME) { + _lastStore = start; + try { + _log.debug("Periodic profile store start"); + storeProfiles(); + _log.debug("Periodic profile store end"); + } catch (Throwable t) { + _log.log(Log.CRIT, "Error storing profiles", t); + } + } long uptime = _context.router().getUptime(); long delay; if (orgtime > 1000 || uptime > 2*60*60*1000) @@ -130,9 +149,16 @@ class PeerManager { } void storeProfiles() { - Set<Hash> peers = selectPeers(); - for (Hash peer : peers) { - storeProfile(peer); + // lock in case shutdown bumps into periodic store + if (!_storeLock.compareAndSet(false, true)) + return; + try { + Set<Hash> peers = selectPeers(); + for (Hash peer : peers) { + storeProfile(peer); + } + } finally { + _storeLock.set(false); } }