diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 0e9e4f2b6..5ae92b09a 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -594,7 +594,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh return output; } - private String intMapToString(HashMap intMap) { + private String intMapToString(Map intMap) { String output = ""; for (String key : intMap.keySet()) { Integer value = intMap.get(key); @@ -612,7 +612,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh return output; } - private HashMap stringToIntMap(String mapString) { + private Map stringToIntMap(String mapString) { HashMap output = new HashMap(); for (String line : mapString.split("\n")) { String[] pair = line.split(" "); @@ -646,12 +646,12 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh return preferences.getBoolean(PREF_PREFER_FOREIGN, false); } - public void setMirrorErrorData(HashMap mirrorErrorMap) { + public void setMirrorErrorData(Map mirrorErrorMap) { preferences.edit().putString(PREF_MIRROR_ERROR_DATA, intMapToString(mirrorErrorMap)).apply(); } - public HashMap getMirrorErrorData() { - HashMap mirrorDataMap = new HashMap(); + public Map getMirrorErrorData() { + Map mirrorDataMap = new HashMap(); String mapString = preferences.getString(PREF_MIRROR_ERROR_DATA, ""); if (mapString == null || mapString.isEmpty()) { // no-op, return empty map to avoid null issues diff --git a/app/src/main/java/org/fdroid/fdroid/net/FDroidMirrorParameterManager.java b/app/src/main/java/org/fdroid/fdroid/net/FDroidMirrorParameterManager.java index 7d8f22234..4716683c9 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/FDroidMirrorParameterManager.java +++ b/app/src/main/java/org/fdroid/fdroid/net/FDroidMirrorParameterManager.java @@ -11,29 +11,32 @@ import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.data.App; +import java.util.Collections; import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class FDroidMirrorParameterManager implements MirrorParameterManager { - private volatile HashMap errorCache; - private static final int DELAY_TIME = 1; + private final ConcurrentHashMap errorCache; + private static final int DELAY_TIME = 5; private static final TimeUnit DELAY_UNIT = TimeUnit.SECONDS; private volatile boolean writeErrorScheduled = false; - - private final Runnable delayedErrorWrite = () -> { - Preferences prefs = Preferences.get(); - prefs.setMirrorErrorData(errorCache); - writeErrorScheduled = false; - }; - + private final Runnable delayedErrorWrite; private final ScheduledExecutorService writeErrorExecutor = Executors.newSingleThreadScheduledExecutor(); public FDroidMirrorParameterManager() { Preferences prefs = Preferences.get(); - errorCache = prefs.getMirrorErrorData(); + errorCache = new ConcurrentHashMap(prefs.getMirrorErrorData()); + delayedErrorWrite = () -> { + Map snapshot = Collections.unmodifiableMap(new HashMap(errorCache)); + Preferences writePrefs = Preferences.get(); + writePrefs.setMirrorErrorData(snapshot); + writeErrorScheduled = false; + }; } public void updateErrorCacheAndPrefs(@NonNull String url, @NonNull Integer errorCount) { diff --git a/app/src/test/java/org/fdroid/fdroid/PreferencesTest.java b/app/src/test/java/org/fdroid/fdroid/PreferencesTest.java index 2eaf48e4a..7d1fa55e9 100644 --- a/app/src/test/java/org/fdroid/fdroid/PreferencesTest.java +++ b/app/src/test/java/org/fdroid/fdroid/PreferencesTest.java @@ -166,7 +166,7 @@ public class PreferencesTest { Preferences preferences = Preferences.get(); // serialize an empty map preferences.setMirrorErrorData(new HashMap<>(0)); - HashMap result = preferences.getMirrorErrorData(); + Map result = preferences.getMirrorErrorData(); // deserializing should return an empty map without throwing any exceptions assertNotNull(result); assertEquals(result.size(), 0);