diff --git a/Spigot-Server-Patches/0363-Optimize-and-Fix-ExpiringMap-Issues.patch b/Spigot-Server-Patches/0363-Optimize-and-Fix-ExpiringMap-Issues.patch index 9b73a189f8..4ac9a732af 100644 --- a/Spigot-Server-Patches/0363-Optimize-and-Fix-ExpiringMap-Issues.patch +++ b/Spigot-Server-Patches/0363-Optimize-and-Fix-ExpiringMap-Issues.patch @@ -1,4 +1,4 @@ -From 7ac07ac07ac07ac07ac07ac07ac07ac07ac07ac0 Mon Sep 17 00:00:00 2001 +From 2d658275fe79491d391314770482c2adaeccd2d7 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 16 Sep 2018 00:00:16 -0400 Subject: [PATCH] Optimize and Fix ExpiringMap Issues @@ -13,24 +13,46 @@ 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/ChunkGeneratorAbstract.java b/src/main/java/net/minecraft/server/ChunkGeneratorAbstract.java +index c8c1444e88..6723343b8b 100644 +--- a/src/main/java/net/minecraft/server/ChunkGeneratorAbstract.java ++++ b/src/main/java/net/minecraft/server/ChunkGeneratorAbstract.java +@@ -143,13 +143,13 @@ public abstract class ChunkGeneratorAbstract implem + + public Long2ObjectMap getStructureStartCache(StructureGenerator structuregenerator) { + return (Long2ObjectMap) this.d.computeIfAbsent(structuregenerator, (s) -> { +- return Long2ObjectMaps.synchronize(new ExpiringMap(8192, 10000)); ++ return new ExpiringMap(8192, 10000); // Paper - already synchronized + }); + } + + public Long2ObjectMap getStructureCache(StructureGenerator structuregenerator) { + return (Long2ObjectMap) this.e.computeIfAbsent(structuregenerator, (s) -> { +- return Long2ObjectMaps.synchronize(new ExpiringMap(8192, 10000)); ++ return new ExpiringMap(8192, 10000); // Paper - already synchronized + }); + } + diff --git a/src/main/java/net/minecraft/server/ExpiringMap.java b/src/main/java/net/minecraft/server/ExpiringMap.java -index 7ac07ac07ac0..7ac07ac07ac0 100644 +index ee97c2b6f6..795e735420 100644 --- a/src/main/java/net/minecraft/server/ExpiringMap.java +++ b/src/main/java/net/minecraft/server/ExpiringMap.java -@@ -2,38 +2,165 @@ package net.minecraft.server; +@@ -2,94 +2,200 @@ 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.ObjectCollection; 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; + import java.util.function.LongFunction; -public class ExpiringMap extends Long2ObjectOpenHashMap { +- +public class ExpiringMap extends Long2ObjectMaps.SynchronizedMap { // paper - synchronize accesss private final int a; - private final Long2LongMap b = new Long2LongLinkedOpenHashMap(); @@ -47,53 +69,57 @@ index 7ac07ac07ac0..7ac07ac07ac0 100644 + private void setAccess(long i) { a(i); } // Paper - OBFHELPER private void a(long i) { - long j = SystemUtils.b(); -- this.b.put(i, j); -- ObjectIterator objectiterator = this.b.long2LongEntrySet().iterator(); -- -- while(objectiterator.hasNext()) { -- Entry entry = (Entry)objectiterator.next(); -- Object object = super.get(entry.getLongKey()); -- if (j - entry.getLongValue() <= (long)this.a) { -- break; + synchronized (this.sync) { + long j = System.currentTimeMillis(); // Paper + this.ttl.put(i, j); + if (!registered) { + registered = true; + MinecraftServer.getServer().expiringMaps.add(this); - } ++ } + } + } +- this.b.put(i, j); +- cleanup(); +- // CraftBukkit start ++ @Override ++ public T compute(long l, BiFunction biFunction) { ++ setAccess(l); ++ return super.compute(l, biFunction); + } + +- public void cleanup() { +- long j = SystemUtils.b(); +- ObjectIterator objectiterator = this.b.long2LongEntrySet().iterator(); // CraftBukkit - decompile error ++ @Override ++ public T putIfAbsent(long l, T t) { ++ setAccess(l); ++ return super.putIfAbsent(l, t); ++ } + +- while (objectiterator.hasNext()) { +- Long2LongMap.Entry entry = (Long2LongMap.Entry) objectiterator.next(); // CraftBukkit - decompile error +- T object = super.get(entry.getLongKey()); // CraftBukkit - decompile error ++ @Override ++ public T computeIfPresent(long l, BiFunction biFunction) { ++ setAccess(l); ++ return super.computeIfPresent(l, biFunction); ++ } + +- if (j - entry.getLongValue() <= (long) this.a) { +- break; +- } ++ @Override ++ public T computeIfAbsent(long l, LongFunction longFunction) { ++ setAccess(l); ++ return super.computeIfAbsent(l, longFunction); ++ } + - if (object != null && this.a(object)) { - super.remove(entry.getLongKey()); - objectiterator.remove(); - } + @Override -+ public T compute(long l, BiFunction biFunction) { -+ setAccess(l); -+ return super.compute(l, biFunction); -+ } -+ -+ @Override -+ public T putIfAbsent(long l, T t) { -+ setAccess(l); -+ return super.putIfAbsent(l, t); -+ } -+ -+ @Override -+ public T computeIfPresent(long l, BiFunction biFunction) { -+ setAccess(l); -+ return super.computeIfPresent(l, biFunction); -+ } -+ -+ @Override -+ public T computeIfAbsent(long l, LongFunction longFunction) { -+ setAccess(l); -+ return super.computeIfAbsent(l, longFunction); -+ } -+ -+ @Override + public boolean replace(long l, T t, T v1) { + setAccess(l); + return super.replace(l, t, v1); @@ -147,6 +173,7 @@ index 7ac07ac07ac0..7ac07ac07ac0 100644 + ttl.clear(); + super.clear(); } +- // CraftBukkit end + } + private boolean registered = false; @@ -199,13 +226,29 @@ index 7ac07ac07ac0..7ac07ac07ac0 100644 + // Paper end } - protected boolean a(T var1) { -@@ -51,8 +178,13 @@ public class ExpiringMap extends Long2ObjectOpenHashMap { +- protected boolean a(T t0) { ++ protected boolean a(T var1) { + return true; + } + +- public T put(long i, T t0) { ++ public T put(long i, T object) { + this.a(i); +- return super.put(i, t0); ++ return (T)super.put(i, object); + } + +- public T put(Long olong, T t0) { +- this.a(olong.longValue()); +- return super.put(olong, t0); ++ public T put(Long olong, T object) { ++ this.a(olong); ++ return (T)super.put(olong, object); } public T get(long i) { - this.a(i); -- return (T)super.get(i); +- return super.get(i); + // Paper start - don't setAccess unless a hit + T t = super.get(i); + if (t != null) { @@ -215,16 +258,44 @@ index 7ac07ac07ac0..7ac07ac07ac0 100644 + // Paper end } - public void putAll(Map var1) { +- public void putAll(Map map) { ++ public void putAll(Map var1) { + throw new RuntimeException("Not implemented"); + } + +- public T remove(long i) { ++ public T remove(long var1) { + throw new RuntimeException("Not implemented"); + } + +- public T remove(Object object) { ++ public T remove(Object var1) { + throw new RuntimeException("Not implemented"); + } +- +- // CraftBukkit start +- @Override +- public T computeIfAbsent(long l, LongFunction lf) { +- this.b.put(l, SystemUtils.b()); +- return super.computeIfAbsent(l, lf); +- } +- +- @Override +- public ObjectCollection values() { +- cleanup(); +- return super.values(); +- } +- // CraftBukkit end + } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7ac07ac07ac0..7ac07ac07ac0 100644 +index d83e85dbff..2105fa50bf 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -155,6 +155,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati public int autosavePeriod; public File bukkitDataPackFolder; public CommandDispatcher vanillaCommandDispatcher; -+ public List expiringMaps = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); // PAper ++ public List expiringMaps = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); // Paper // CraftBukkit end // Spigot start public static final int TPS = 20; @@ -236,6 +307,28 @@ index 7ac07ac07ac0..7ac07ac07ac0 100644 this.slackActivityAccountant.tickEnded(l); // Spigot co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper } +diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +index 9c2adb2351..04e29f58c3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java ++++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +@@ -144,7 +144,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator getStructureStartCache(StructureGenerator structuregenerator) { + return (Long2ObjectMap) this.structureStartCache.computeIfAbsent(structuregenerator, (s) -> { +- return Long2ObjectMaps.synchronize(new ExpiringMap(8192, 10000)); ++ return new ExpiringMap(8192, 10000); // Paper - already synchronized + }); + } + +@@ -154,7 +154,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator getStructureCache(StructureGenerator structuregenerator) { + return (Long2ObjectMap) this.structureCache.computeIfAbsent(structuregenerator, (s) -> { +- return Long2ObjectMaps.synchronize(new ExpiringMap(8192, 10000)); ++ return new ExpiringMap(8192, 10000); // Paper - already synchronized + }); + } + -- 2.19.1 diff --git a/work/CraftBukkit b/work/CraftBukkit index f0398e444e..e693496c17 160000 --- a/work/CraftBukkit +++ b/work/CraftBukkit @@ -1 +1 @@ -Subproject commit f0398e444e43a9c63249e668eb85f5fecbb4b6db +Subproject commit e693496c17562b3e865b545f755562bcad81f2e8