Skip to content

Instantly share code, notes, and snippets.

@aikar
Created February 23, 2019 18:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aikar/f49298c90ad1b11f2798ff4d3e69245e to your computer and use it in GitHub Desktop.
Save aikar/f49298c90ad1b11f2798ff4d3e69245e to your computer and use it in GitHub Desktop.
diff --git a/src/main/java/co/aikar/timings/TimingIdentifier.java b/src/main/java/co/aikar/timings/TimingIdentifier.java
index a7f1f44d..7b0325d2 100644
--- a/src/main/java/co/aikar/timings/TimingIdentifier.java
+++ b/src/main/java/co/aikar/timings/TimingIdentifier.java
@@ -24,12 +24,13 @@
package co.aikar.timings;
import co.aikar.util.LoadingMap;
-import co.aikar.util.MRUMapCache;
import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -41,7 +42,7 @@ final class TimingIdentifier {
/**
* Holds all groups. Autoloads on request for a group by name.
*/
- static final Map<String, TimingGroup> GROUP_MAP = LoadingMap.of(new ConcurrentHashMap<>(64, .5F), TimingGroup::new);
+ static final Map<String, TimingGroup> GROUP_MAP = LoadingMap.of(new HashMap<>(64, .5F), TimingGroup::new);
private static final TimingGroup DEFAULT_GROUP = getGroup("Minecraft");
final String group;
final String name;
@@ -84,7 +85,7 @@ final class TimingIdentifier {
final int id = idPool.getAndIncrement();
final String name;
- ArrayDeque<TimingHandler> handlers = new ArrayDeque<TimingHandler>(64);
+ List<TimingHandler> handlers = new CopyOnWriteArrayList<>();
private TimingGroup(String name) {
this.name = name;
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
index df7f4259..9eb96f86 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -153,15 +153,17 @@ class TimingsExport extends Thread {
Map handlers = createObject();
- for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
- for (TimingHandler id : group.handlers) {
- if (!id.isTimed() && !id.isSpecial()) {
- continue;
+ synchronized (TimingIdentifier.GROUP_MAP) {
+ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
+ for (TimingHandler id : group.handlers) {
+ if (!id.isTimed() && !id.isSpecial()) {
+ continue;
+ }
+ handlers.put(id.id, toArray(
+ group.id,
+ id.name
+ ));
}
- handlers.put(id.id, toArray(
- group.id,
- id.name
- ));
}
}
diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java
index f63e7033..5822d424 100644
--- a/src/main/java/co/aikar/timings/TimingsManager.java
+++ b/src/main/java/co/aikar/timings/TimingsManager.java
@@ -23,27 +23,25 @@
*/
package co.aikar.timings;
+import co.aikar.util.LoadingMap;
import com.google.common.collect.EvictingQueue;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.PluginClassLoader;
-import co.aikar.util.LoadingMap;
import javax.annotation.Nullable;
-import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
public final class TimingsManager {
static final Map<TimingIdentifier, TimingHandler> TIMING_MAP = LoadingMap.of(
- new ConcurrentHashMap<>(4096, .5F), TimingHandler::new
+ new HashMap<>(4096, .5F), TimingHandler::new
);
public static final FullServerTickHandler FULL_SERVER_TICK = new FullServerTickHandler();
public static final TimingHandler TIMINGS_TICK = Timings.ofSafe("Timings Tick", FULL_SERVER_TICK);
@@ -51,7 +49,7 @@ public final class TimingsManager {
public static List<String> hiddenConfigs = new ArrayList<String>();
public static boolean privacy = false;
- static final List<TimingHandler> HANDLERS = new ArrayList<>(1024);
+ static final List<TimingHandler> HANDLERS = new CopyOnWriteArrayList<>();
static final List<TimingHistory.MinuteReport> MINUTE_REPORTS = new ArrayList<>(64);
static EvictingQueue<TimingHistory> HISTORY = EvictingQueue.create(12);
diff --git a/src/main/java/co/aikar/util/LoadingMap.java b/src/main/java/co/aikar/util/LoadingMap.java
index 9a4f9dca..111ec139 100644
--- a/src/main/java/co/aikar/util/LoadingMap.java
+++ b/src/main/java/co/aikar/util/LoadingMap.java
@@ -50,6 +50,7 @@ import java.util.function.Function;
public class LoadingMap <K, V> extends AbstractMap<K, V> {
private final Map<K, V> backingMap;
private final java.util.function.Function<K, V> loader;
+ private final boolean safeGet;
/**
* Initializes an auto loading map using specified loader and backing map
@@ -57,8 +58,19 @@ public class LoadingMap <K, V> extends AbstractMap<K, V> {
* @param loader Loader
*/
public LoadingMap(Map<K, V> backingMap, java.util.function.Function<K, V> loader) {
+ this(backingMap, loader, true);
+ }
+
+ /**
+ * Initializes an auto loading map using specified loader and backing map
+ * @param backingMap Map to wrap
+ * @param loader Loader
+ * @param safeGet Use synchronization on get calls on miss for thread safety
+ */
+ public LoadingMap(Map<K, V> backingMap, java.util.function.Function<K, V> loader, boolean safeGet) {
this.backingMap = backingMap;
this.loader = loader;
+ this.safeGet = safeGet;
}
/**
@@ -74,6 +86,20 @@ public class LoadingMap <K, V> extends AbstractMap<K, V> {
return new LoadingMap<>(backingMap, loader);
}
+ /**
+ * Creates a new LoadingMap with the specified map and loader
+ *
+ * @param backingMap Actual map being used.
+ * @param loader Loader to use
+ * @param safeGet Use synchronization on get calls on miss for thread safety
+ * @param <K> Key Type of the Map
+ * @param <V> Value Type of the Map
+ * @return Map
+ */
+ public static <K, V> Map<K, V> of(Map<K, V> backingMap, Function<K, V> loader, boolean safeGet) {
+ return new LoadingMap<>(backingMap, loader, safeGet);
+ }
+
/**
* Creates a LoadingMap with an auto instantiating loader.
*
@@ -251,6 +277,15 @@ public class LoadingMap <K, V> extends AbstractMap<K, V> {
@Override
public V get(Object key) {
+ if (safeGet) {
+ V v = backingMap.get(key);
+ if (v != null) {
+ return v;
+ }
+ synchronized (this) {
+ return backingMap.computeIfAbsent((K) key, loader);
+ }
+ }
return backingMap.computeIfAbsent((K) key, loader);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment