diff --git a/Spigot-Server-Patches/Optimize-and-Fix-ExpiringMap-Issues.patch b/Spigot-Server-Patches/Optimize-and-Fix-ExpiringMap-Issues.patch index bd7c949713..c9c50bb880 100644 --- a/Spigot-Server-Patches/Optimize-and-Fix-ExpiringMap-Issues.patch +++ b/Spigot-Server-Patches/Optimize-and-Fix-ExpiringMap-Issues.patch @@ -13,8 +13,28 @@ 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 +@@ -0,0 +0,0 @@ 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 @@ -0,0 +0,0 @@ package net.minecraft.server; @@ -24,13 +44,15 @@ index 7ac07ac07ac0..7ac07ac07ac0 100644 +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) { -@@ -0,0 +0,0 @@ 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 @@ -0,0 +0,0 @@ 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,4 +307,26 @@ 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 +@@ -0,0 +0,0 @@ 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 + }); + } + +@@ -0,0 +0,0 @@ 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 + }); + } + -- \ No newline at end of file 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