Fix concurrency issues with ExpiringMap

This commit is contained in:
Aikar 2018-09-20 11:43:32 -04:00
parent 8e847f5300
commit ec6b72db98

View file

@ -1,34 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 16 Sep 2018 00:00:16 -0400
Subject: [PATCH] Fix major memory leaks in ExpiringMap
Subject: [PATCH] Optimize and Fix ExpiringMap Issues
computeIfAbsent would leak as the entry
was never registered into the ttl map
computeIfAbsent would leak as the entry was never
registered into the ttl map, as well as some other
methods were at risk, so they were added.
This fixes that ,as well as redesigns cleaning to
not run on every manipulation, and instead to run clean
once per tick per expiring map.
This also synchronizes all access make the map thread safe.
This also redesigns cleaning to not run on every
manipulation, and instead to run clean
once per tick per active expiring map.
diff --git a/src/main/java/net/minecraft/server/ExpiringMap.java b/src/main/java/net/minecraft/server/ExpiringMap.java
index 4006f5a69c..d64c143017 100644
index 4006f5a69c..9a3b35ea1a 100644
--- a/src/main/java/net/minecraft/server/ExpiringMap.java
+++ b/src/main/java/net/minecraft/server/ExpiringMap.java
@@ -0,0 +0,0 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2LongMap.Entry;
@@ -0,0 +0,0 @@ package net.minecraft.server;
import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2LongMap.Entry;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.LongFunction;
public class ExpiringMap<T> extends Long2ObjectOpenHashMap<T> {
-public class ExpiringMap<T> extends Long2ObjectOpenHashMap<T> {
+public class ExpiringMap<T> extends Long2ObjectMaps.SynchronizedMap<T> { // paper - synchronize accesss
private final int a;
- private final Long2LongMap b = new Long2LongLinkedOpenHashMap();
+ private final Long2LongMap ttl = new Long2LongLinkedOpenHashMap(); // Paper
public ExpiringMap(int i, int j) {
super(i);
- super(i);
+ super(new Long2ObjectOpenHashMap<>(i)); // Paper
this.a = j;
}
@ -160,6 +170,10 @@ index 4006f5a69c..d64c143017 100644
+ ttl.putIfAbsent(entry.getLongKey(), now);
+ }
+ } catch (Exception e) { } // Ignore any como's
+ } else if (ttlSize > this.size()) {
+ try {
+ this.ttl.long2LongEntrySet().removeIf(entry -> !this.containsKey(entry.getLongKey()));
+ } catch (Exception e) { } // Ignore any como's
+ }
+ if (isEmpty()) {
+ registered = false;
@ -175,10 +189,17 @@ index 4006f5a69c..d64c143017 100644
public T get(long i) {
- this.a(i);
+ if (ttl.containsKey(i)) this.setAccess(i); // Paper
return (T)super.get(i);
- return (T)super.get(i);
+ // Paper start - don't setAccess unless a hit
+ T t = super.get(i);
+ if (t != null) {
+ this.setAccess(i);
+ }
+ return t;
+ // Paper end
}
public void putAll(Map<? extends Long, ? extends T> var1) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index eb3fc836fb..81cda5df56 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java