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
         }
     }
 }