From 6a72c2957b59e68df415f79849c999c2abcf1abe Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sat, 12 Nov 2016 22:27:34 +0000
Subject: [PATCH] Profiles: Periodically save (ticket #1328)

---
 .../i2p/router/peermanager/PeerManager.java   | 34 ++++++++++++++++---
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java
index b3cc3643b0..d3f2986e85 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);
         }
     }
 
-- 
GitLab