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/world/level/lighting/LightEngineStorage.java b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/lighting/LightEngineStorage.java +++ b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorage.java @@ -0,0 +0,0 @@ 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()); @@ -0,0 +0,0 @@ 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) { @@ -0,0 +0,0 @@ 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 @@ -0,0 +0,0 @@ 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/world/level/lighting/LightEngineStorageArray.java b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageArray.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageArray.java +++ b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageArray.java @@ -0,0 +0,0 @@ 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; } @@ -0,0 +0,0 @@ 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]) { @@ -0,0 +0,0 @@ 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; @@ -0,0 +0,0 @@ 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() { @@ -0,0 +0,0 @@ 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/world/level/lighting/LightEngineStorageBlock.java b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageBlock.java +++ b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageBlock.java @@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.NibbleArray; 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 @@ -0,0 +0,0 @@ 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/world/level/lighting/LightEngineStorageSky.java b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageSky.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageSky.java +++ b/src/main/java/net/minecraft/world/level/lighting/LightEngineStorageSky.java @@ -0,0 +0,0 @@ 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 @@ -0,0 +0,0 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage } else { return 15; } + } // Paper - avoid copying light data } @Override @@ -0,0 +0,0 @@ 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) { @@ -0,0 +0,0 @@ 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)) { @@ -0,0 +0,0 @@ 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 } } @@ -0,0 +0,0 @@ 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)); @@ -0,0 +0,0 @@ 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; @@ -0,0 +0,0 @@ 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; } @@ -0,0 +0,0 @@ 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; } @@ -0,0 +0,0 @@ public class LightEngineStorageSky extends LightEngineStorage<LightEngineStorage public static final class a extends LightEngineStorageArray<LightEngineStorageSky.a> { private int b; - private final Long2IntOpenHashMap c; - - public a(Long2ObjectOpenHashMap<NibbleArray> long2objectopenhashmap, Long2IntOpenHashMap long2intopenhashmap, int i) { - super(long2objectopenhashmap); - this.c = long2intopenhashmap; - long2intopenhashmap.defaultReturnValue(i); + private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data + + // 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; + otherData.queueDefaultReturnValue(i); + // 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 } } }