From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf <spottedleaf@spottedleaf.dev> Date: Mon, 27 Apr 2020 04:05:38 -0700 Subject: [PATCH] Stop copy-on-write operations for updating light data Causes huge memory allocations + gc issues diff --git a/src/main/java/net/minecraft/server/LightEngineStorage.java b/src/main/java/net/minecraft/server/LightEngineStorage.java index a3f919816eb2a742ed09b553995e6508684e5ea5..88277d23c36696fdd5363e41a130c9a443fac2c0 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorage.java +++ b/src/main/java/net/minecraft/server/LightEngineStorage.java @@ -19,8 +19,8 @@ public abstract class LightEngineStorage<M extends LightEngineStorageArray<M>> e protected final LongSet b = new LongOpenHashSet(); protected final LongSet c = new LongOpenHashSet(); protected final LongSet d = new LongOpenHashSet(); - protected volatile M e; - protected final M f; + protected volatile M e_visible; protected final Object visibleUpdateLock = new Object(); // Paper - diff on change, should be "visible" - force compile fail on usage change + protected final M f; // Paper - diff on change, should be "updating" protected final LongSet g = new LongOpenHashSet(); protected final LongSet h = new LongOpenHashSet(); protected final Long2ObjectMap<NibbleArray> i = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap()); @@ -33,8 +33,8 @@ public abstract class LightEngineStorage<M extends LightEngineStorageArray<M>> e this.l = enumskyblock; this.m = ilightaccess; this.f = m0; - this.e = m0.b(); - this.e.d(); + this.e_visible = m0.b(); // Paper - avoid copying light data + this.e_visible.d(); // Paper - avoid copying light data } protected boolean g(long i) { @@ -43,7 +43,15 @@ public abstract class LightEngineStorage<M extends LightEngineStorageArray<M>> e @Nullable protected NibbleArray a(long i, boolean flag) { - return this.a(flag ? this.f : this.e, i); + // Paper start - avoid copying light data + if (flag) { + return this.a(this.f, i); + } else { + synchronized (this.visibleUpdateLock) { + return this.a(this.e_visible, i); + } + } + // Paper end - avoid copying light data } @Nullable @@ -340,10 +348,12 @@ public abstract class LightEngineStorage<M extends LightEngineStorageArray<M>> e protected void e() { if (!this.g.isEmpty()) { + synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data M m0 = this.f.b(); m0.d(); - this.e = m0; + this.e_visible = m0; // Paper - avoid copying light data + } // Paper - avoid copying light data this.g.clear(); } diff --git a/src/main/java/net/minecraft/server/LightEngineStorageArray.java b/src/main/java/net/minecraft/server/LightEngineStorageArray.java index b978723a66d001f70325df0c7521025e079d7cfa..53199595da71a25710bd1ff8ee2868ee63edc0e1 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorageArray.java +++ b/src/main/java/net/minecraft/server/LightEngineStorageArray.java @@ -8,10 +8,23 @@ public abstract class LightEngineStorageArray<M extends LightEngineStorageArray< private final long[] b = new long[2]; private final NibbleArray[] c = new NibbleArray[2]; private boolean d; - protected final Long2ObjectOpenHashMap<NibbleArray> a; - - protected LightEngineStorageArray(Long2ObjectOpenHashMap<NibbleArray> long2objectopenhashmap) { - this.a = long2objectopenhashmap; + protected final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<NibbleArray> data; // Paper - avoid copying light data + protected final boolean isVisible; // Paper - avoid copying light data + java.util.function.Function<Long, NibbleArray> lookup; // Paper - faster branchless lookup + + // Paper start - avoid copying light data + protected LightEngineStorageArray(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<NibbleArray> data, boolean isVisible) { + if (isVisible) { + data.performUpdatesLockMap(); + } + this.data = data; + this.isVisible = isVisible; + if (isVisible) { + lookup = data::getVisibleAsync; + } else { + lookup = data::getUpdating; + } + // Paper end - avoid copying light data this.c(); this.d = true; } @@ -19,16 +32,17 @@ public abstract class LightEngineStorageArray<M extends LightEngineStorageArray< public abstract M b(); public void a(long i) { - this.a.put(i, ((NibbleArray) this.a.get(i)).b()); + if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data + this.data.queueUpdate(i, ((NibbleArray) this.data.getUpdating(i)).b()); // Paper - avoid copying light data this.c(); } public boolean b(long i) { - return this.a.containsKey(i); + return lookup.apply(i) != null; // Paper - avoid copying light data } @Nullable - public NibbleArray c(long i) { + public final NibbleArray c(long i) { // Paper - final if (this.d) { for (int j = 0; j < 2; ++j) { if (i == this.b[j]) { @@ -37,7 +51,7 @@ public abstract class LightEngineStorageArray<M extends LightEngineStorageArray< } } - NibbleArray nibblearray = (NibbleArray) this.a.get(i); + NibbleArray nibblearray = lookup.apply(i); // Paper - avoid copying light data if (nibblearray == null) { return null; @@ -58,11 +72,13 @@ public abstract class LightEngineStorageArray<M extends LightEngineStorageArray< @Nullable public NibbleArray d(long i) { - return (NibbleArray) this.a.remove(i); + if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data + return (NibbleArray) this.data.queueRemove(i); // Paper - avoid copying light data } public void a(long i, NibbleArray nibblearray) { - this.a.put(i, nibblearray); + if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data + this.data.queueUpdate(i, nibblearray); // Paper - avoid copying light data } public void c() { @@ -70,7 +86,6 @@ public abstract class LightEngineStorageArray<M extends LightEngineStorageArray< this.b[i] = Long.MAX_VALUE; this.c[i] = null; } - } public void d() { diff --git a/src/main/java/net/minecraft/server/LightEngineStorageBlock.java b/src/main/java/net/minecraft/server/LightEngineStorageBlock.java index 0f7f4744d9f9e5174fb38ccc72248397a4b064ea..292d8c742d3be41ba8ad7fb7f1251dc7f790b62b 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorageBlock.java +++ b/src/main/java/net/minecraft/server/LightEngineStorageBlock.java @@ -5,7 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; public class LightEngineStorageBlock extends LightEngineStorage<LightEngineStorageBlock.a> { protected LightEngineStorageBlock(ILightAccess ilightaccess) { - super(EnumSkyBlock.BLOCK, ilightaccess, new LightEngineStorageBlock.a(new Long2ObjectOpenHashMap())); + super(EnumSkyBlock.BLOCK, ilightaccess, new LightEngineStorageBlock.a(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), false)); // Paper - avoid copying light data } @Override @@ -18,13 +18,13 @@ public class LightEngineStorageBlock extends LightEngineStorage<LightEngineStora public static final class a extends LightEngineStorageArray<LightEngineStorageBlock.a> { - public a(Long2ObjectOpenHashMap<NibbleArray> long2objectopenhashmap) { - super(long2objectopenhashmap); + public a(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<NibbleArray> long2objectopenhashmap, boolean isVisible) { // Paper - avoid copying light data + super(long2objectopenhashmap, isVisible); // Paper - avoid copying light data } @Override public LightEngineStorageBlock.a b() { - return new LightEngineStorageBlock.a(this.a.clone()); + return new a(this.data, true); // Paper - avoid copying light data } } } diff --git a/src/main/java/net/minecraft/server/LightEngineStorageSky.java b/src/main/java/net/minecraft/server/LightEngineStorageSky.java index 75d9065b32731dc635d9d09c48fb9643172381a9..06bc8371fe9de4d23fdd47e5a3919541bb399fd8 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorageSky.java +++ b/src/main/java/net/minecraft/server/LightEngineStorageSky.java @@ -17,15 +17,16 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage private volatile boolean p; protected LightEngineStorageSky(ILightAccess ilightaccess) { - super(EnumSkyBlock.SKY, ilightaccess, new LightEngineStorageSky.a(new Long2ObjectOpenHashMap(), new Long2IntOpenHashMap(), Integer.MAX_VALUE)); + super(EnumSkyBlock.SKY, ilightaccess, new LightEngineStorageSky.a(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int(), Integer.MAX_VALUE, false)); // Paper - avoid copying light data } @Override protected int d(long i) { long j = SectionPosition.e(i); int k = SectionPosition.c(j); - LightEngineStorageSky.a lightenginestoragesky_a = (LightEngineStorageSky.a) this.e; - int l = lightenginestoragesky_a.c.get(SectionPosition.f(j)); + synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data + LightEngineStorageSky.a lightenginestoragesky_a = (LightEngineStorageSky.a) this.e_visible; // Paper - avoid copying light data - must be after lock acquire + int l = lightenginestoragesky_a.otherData.getVisibleAsync(SectionPosition.f(j)); // Paper - avoid copying light data if (l != lightenginestoragesky_a.b && k < l) { NibbleArray nibblearray = this.a(lightenginestoragesky_a, j); // Paper - decompile fix @@ -46,6 +47,7 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage } else { return 15; } + } // Paper - avoid copying light data } @Override @@ -54,14 +56,14 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage if (((LightEngineStorageSky.a) this.f).b > j) { ((LightEngineStorageSky.a) this.f).b = j; - ((LightEngineStorageSky.a) this.f).c.defaultReturnValue(((LightEngineStorageSky.a) this.f).b); + ((LightEngineStorageSky.a) this.f).otherData.queueDefaultReturnValue(((LightEngineStorageSky.a) this.f).b); // Paper - avoid copying light data } long k = SectionPosition.f(i); - int l = ((LightEngineStorageSky.a) this.f).c.get(k); + int l = ((LightEngineStorageSky.a) this.f).otherData.getUpdating(k); // Paper - avoid copying light data if (l < j + 1) { - ((LightEngineStorageSky.a) this.f).c.put(k, j + 1); + ((LightEngineStorageSky.a) this.f).otherData.queueUpdate(k, j + 1); // Paper - avoid copying light data if (this.o.contains(k)) { this.q(i); if (l > ((LightEngineStorageSky.a) this.f).b) { @@ -101,7 +103,7 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage int k = SectionPosition.c(i); - if (((LightEngineStorageSky.a) this.f).c.get(j) == k + 1) { + if (((LightEngineStorageSky.a) this.f).otherData.getUpdating(j) == k + 1) { // Paper - avoid copying light data long l; for (l = i; !this.g(l) && this.a(k); l = SectionPosition.a(l, EnumDirection.DOWN)) { @@ -109,12 +111,12 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage } if (this.g(l)) { - ((LightEngineStorageSky.a) this.f).c.put(j, k + 1); + ((LightEngineStorageSky.a) this.f).otherData.queueUpdate(j, k + 1); // Paper - avoid copying light data if (flag) { this.q(l); } } else { - ((LightEngineStorageSky.a) this.f).c.remove(j); + ((LightEngineStorageSky.a) this.f).otherData.queueRemove(j); // Paper - avoid copying light data } } @@ -128,7 +130,7 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage protected void b(long i, boolean flag) { this.d(); if (flag && this.o.add(i)) { - int j = ((LightEngineStorageSky.a) this.f).c.get(i); + int j = ((LightEngineStorageSky.a) this.f).otherData.getUpdating(i); // Paper - avoid copying light data if (j != ((LightEngineStorageSky.a) this.f).b) { long k = SectionPosition.b(SectionPosition.b(i), j - 1, SectionPosition.d(i)); @@ -155,7 +157,7 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage return nibblearray; } else { long j = SectionPosition.a(i, EnumDirection.UP); - int k = ((LightEngineStorageSky.a) this.f).c.get(SectionPosition.f(i)); + int k = ((LightEngineStorageSky.a) this.f).otherData.getUpdating(SectionPosition.f(i)); // Paper - avoid copying light data if (k != ((LightEngineStorageSky.a) this.f).b && SectionPosition.c(j) < k) { NibbleArray nibblearray1; @@ -298,7 +300,7 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage if (!this.o.contains(l)) { return false; } else { - int i1 = ((LightEngineStorageSky.a) this.f).c.get(l); + int i1 = ((LightEngineStorageSky.a) this.f).otherData.getUpdating(l); // Paper - avoid copying light data return SectionPosition.c(i1) == j + 16; } @@ -307,7 +309,7 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage protected boolean n(long i) { long j = SectionPosition.f(i); - int k = ((LightEngineStorageSky.a) this.f).c.get(j); + int k = ((LightEngineStorageSky.a) this.f).otherData.getUpdating(j); // Paper - avoid copying light data return k == ((LightEngineStorageSky.a) this.f).b || SectionPosition.c(i) >= k; } @@ -321,18 +323,20 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage public static final class a extends LightEngineStorageArray<LightEngineStorageSky.a> { private int b; - private final Long2IntOpenHashMap c; + private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data - public a(Long2ObjectOpenHashMap<NibbleArray> long2objectopenhashmap, Long2IntOpenHashMap long2intopenhashmap, int i) { - super(long2objectopenhashmap); - this.c = long2intopenhashmap; - long2intopenhashmap.defaultReturnValue(i); + // Paper start - avoid copying light data + public a(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<NibbleArray> data, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData, int i, boolean isVisible) { + super(data, isVisible); + this.otherData = otherData; + // Paper end - avoid copying light data this.b = i; } @Override public LightEngineStorageSky.a b() { - return new LightEngineStorageSky.a(this.a.clone(), this.c.clone(), this.b); + this.otherData.performUpdatesLockMap(); // Paper - avoid copying light data + return new LightEngineStorageSky.a(this.data, this.otherData, this.b, true); // Paper - avoid copying light data } } }