aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0451-Stop-copy-on-write-operations-for-updating-light-dat.patch
blob: 74e5860e6be6b4424b12fac6f3ec87f7d93d948e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
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/BlockLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
index 573cdb0897978eef8f5fc906ed4928293f4b2ab9..314b46f0becd088d26956b45981217b128d539cb 100644
--- a/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/BlockLightSectionStorage.java
@@ -9,7 +9,7 @@ import net.minecraft.world.level.chunk.LightChunkGetter;
 
 public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLightSectionStorage.BlockDataLayerStorageMap> {
     protected BlockLightSectionStorage(LightChunkGetter chunkProvider) {
-        super(LightLayer.BLOCK, chunkProvider, new BlockLightSectionStorage.BlockDataLayerStorageMap(new Long2ObjectOpenHashMap<>()));
+        super(LightLayer.BLOCK, chunkProvider, new BlockLightSectionStorage.BlockDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), false)); // Paper - avoid copying light data
     }
 
     @Override
@@ -20,13 +20,13 @@ public class BlockLightSectionStorage extends LayerLightSectionStorage<BlockLigh
     }
 
     protected static final class BlockDataLayerStorageMap extends DataLayerStorageMap<BlockLightSectionStorage.BlockDataLayerStorageMap> {
-        public BlockDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
-            super(arrays);
+        public BlockDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> long2objectopenhashmap, boolean isVisible) { // Paper - avoid copying light data
+            super(long2objectopenhashmap, isVisible); // Paper - avoid copying light data
         }
 
         @Override
         public BlockLightSectionStorage.BlockDataLayerStorageMap copy() {
-            return new BlockLightSectionStorage.BlockDataLayerStorageMap(this.map.clone());
+            return new BlockDataLayerStorageMap(this.data, true); // Paper - avoid copying light data
         }
     }
 }
diff --git a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
index 67ff66e232592203cf8dad605ad01eabc4dded89..f357a3473682c2d37a20fb862522c67b9979402a 100644
--- a/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
+++ b/src/main/java/net/minecraft/world/level/lighting/DataLayerStorageMap.java
@@ -9,10 +9,23 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
     private final long[] lastSectionKeys = new long[2];
     private final DataLayer[] lastSections = new DataLayer[2];
     private boolean cacheEnabled;
-    protected final Long2ObjectOpenHashMap<DataLayer> map;
+    protected final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> data; // Paper - avoid copying light data
+    protected final boolean isVisible; // Paper - avoid copying light data
+    java.util.function.Function<Long, DataLayer> lookup; // Paper - faster branchless lookup
 
-    protected DataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays) {
-        this.map = arrays;
+    // Paper start - avoid copying light data
+    protected DataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> 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.clearCache();
         this.cacheEnabled = true;
     }
@@ -20,16 +33,17 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
     public abstract M copy();
 
     public void copyDataLayer(long pos) {
-        this.map.put(pos, this.map.get(pos).copy());
+        if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
+        this.data.queueUpdate(pos, ((DataLayer) this.data.getUpdating(pos)).copy()); // Paper - avoid copying light data
         this.clearCache();
     }
 
     public boolean hasLayer(long chunkPos) {
-        return this.map.containsKey(chunkPos);
+        return lookup.apply(chunkPos) != null; // Paper - avoid copying light data
     }
 
     @Nullable
-    public DataLayer getLayer(long chunkPos) {
+    public final DataLayer getLayer(long chunkPos) { // Paper - final
         if (this.cacheEnabled) {
             for(int i = 0; i < 2; ++i) {
                 if (chunkPos == this.lastSectionKeys[i]) {
@@ -38,7 +52,7 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
             }
         }
 
-        DataLayer dataLayer = this.map.get(chunkPos);
+        DataLayer dataLayer = lookup.apply(chunkPos); // Paper - avoid copying light data
         if (dataLayer == null) {
             return null;
         } else {
@@ -58,11 +72,13 @@ public abstract class DataLayerStorageMap<M extends DataLayerStorageMap<M>> {
 
     @Nullable
     public DataLayer removeLayer(long chunkPos) {
-        return this.map.remove(chunkPos);
+        if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
+        return (DataLayer) this.data.queueRemove(chunkPos); // Paper - avoid copying light data
     }
 
     public void setLayer(long pos, DataLayer data) {
-        this.map.put(pos, data);
+        if (this.isVisible) { throw new IllegalStateException("writing to visible data"); } // Paper - avoid copying light data
+        this.data.queueUpdate(pos, data); // Paper - avoid copying light data
     }
 
     public void clearCache() {
diff --git a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
index c899674ee24167ee3abdf1588d7396df0ab4f0aa..85175b01b1623b3bc66c65805cec26eaead48265 100644
--- a/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/LayerLightSectionStorage.java
@@ -27,7 +27,7 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
     protected final LongSet dataSectionSet = new LongOpenHashSet();
     protected final LongSet toMarkNoData = new LongOpenHashSet();
     protected final LongSet toMarkData = new LongOpenHashSet();
-    protected volatile M visibleSectionData;
+    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 updatingSectionData;
     protected final LongSet changedSections = new LongOpenHashSet();
     protected final LongSet sectionsAffectedByLightUpdates = new LongOpenHashSet();
@@ -42,8 +42,8 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
         this.layer = lightType;
         this.chunkSource = chunkProvider;
         this.updatingSectionData = lightData;
-        this.visibleSectionData = lightData.copy();
-        this.visibleSectionData.disableCache();
+        this.e_visible = lightData.copy(); // Paper - avoid copying light dat
+        this.e_visible.disableCache(); // Paper - avoid copying light dat
     }
 
     protected boolean storingLightForSection(long sectionPos) {
@@ -52,7 +52,15 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
 
     @Nullable
     protected DataLayer getDataLayer(long sectionPos, boolean cached) {
-        return this.getDataLayer((M)(cached ? this.updatingSectionData : this.visibleSectionData), sectionPos);
+        // Paper start - avoid copying light data
+        if (cached) {
+            return this.getDataLayer(this.updatingSectionData, sectionPos);
+        } else {
+            synchronized (this.visibleUpdateLock) {
+                return this.getDataLayer(this.e_visible, sectionPos);
+            }
+        }
+        // Paper end - avoid copying light data
     }
 
     @Nullable
@@ -342,9 +350,11 @@ public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>>
 
     protected void swapSectionMap() {
         if (!this.changedSections.isEmpty()) {
+            synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
             M dataLayerStorageMap = this.updatingSectionData.copy();
             dataLayerStorageMap.disableCache();
-            this.visibleSectionData = dataLayerStorageMap;
+            this.e_visible = dataLayerStorageMap; // Paper - avoid copying light data
+            } // Paper - avoid copying light data
             this.changedSections.clear();
         }
 
diff --git a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
index 59d2af9f883541518c203302257f03dbe957aa0b..e6c857c8b4e4e65e3cf6a75ce6d844ff61acb566 100644
--- a/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/lighting/SkyLightSectionStorage.java
@@ -21,7 +21,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
     private volatile boolean hasSourceInconsistencies;
 
     protected SkyLightSectionStorage(LightChunkGetter chunkProvider) {
-        super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new Long2ObjectOpenHashMap<>(), new Long2IntOpenHashMap(), Integer.MAX_VALUE));
+        super(LightLayer.SKY, chunkProvider, new SkyLightSectionStorage.SkyDataLayerStorageMap(new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<>(), new com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int(), Integer.MAX_VALUE, false)); // Paper - avoid copying light data
     }
 
     @Override
@@ -32,8 +32,9 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
     protected int getLightValue(long blockPos, boolean cached) {
         long l = SectionPos.blockToSection(blockPos);
         int i = SectionPos.y(l);
-        SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = cached ? this.updatingSectionData : this.visibleSectionData;
-        int j = skyDataLayerStorageMap.topSections.get(SectionPos.getZeroNode(l));
+        synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data
+        SkyLightSectionStorage.SkyDataLayerStorageMap skyDataLayerStorageMap = (SkyLightSectionStorage.SkyDataLayerStorageMap) this.e_visible; // Paper - avoid copying light data - must be after lock acquire
+        int j = skyDataLayerStorageMap.otherData.getVisibleAsync(SectionPos.getZeroNode(l)); // Paper - avoid copying light data
         if (j != skyDataLayerStorageMap.currentLowestY && i < j) {
             DataLayer dataLayer = this.getDataLayer(skyDataLayerStorageMap, l);
             if (dataLayer == null) {
@@ -52,6 +53,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
         } else {
             return cached && !this.lightOnInSection(l) ? 0 : 15;
         }
+        } // Paper - avoid copying light data
     }
 
     @Override
@@ -59,13 +61,13 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
         int i = SectionPos.y(sectionPos);
         if ((this.updatingSectionData).currentLowestY > i) {
             (this.updatingSectionData).currentLowestY = i;
-            (this.updatingSectionData).topSections.defaultReturnValue((this.updatingSectionData).currentLowestY);
+            (this.updatingSectionData).otherData.queueDefaultReturnValue((this.updatingSectionData).currentLowestY); // Paper - avoid copying light data
         }
 
         long l = SectionPos.getZeroNode(sectionPos);
-        int j = (this.updatingSectionData).topSections.get(l);
+        int j = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
         if (j < i + 1) {
-            (this.updatingSectionData).topSections.put(l, i + 1);
+            (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
             if (this.columnsWithSkySources.contains(l)) {
                 this.queueAddSource(sectionPos);
                 if (j > (this.updatingSectionData).currentLowestY) {
@@ -102,19 +104,19 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
         }
 
         int i = SectionPos.y(sectionPos);
-        if ((this.updatingSectionData).topSections.get(l) == i + 1) {
+        if ((this.updatingSectionData).otherData.getUpdating(l) == i + 1) { // Paper - avoid copying light data
             long m;
             for(m = sectionPos; !this.storingLightForSection(m) && this.hasSectionsBelow(i); m = SectionPos.offset(m, Direction.DOWN)) {
                 --i;
             }
 
             if (this.storingLightForSection(m)) {
-                (this.updatingSectionData).topSections.put(l, i + 1);
+                (this.updatingSectionData).otherData.queueUpdate(l, i + 1); // Paper - avoid copying light data
                 if (bl) {
                     this.queueAddSource(m);
                 }
             } else {
-                (this.updatingSectionData).topSections.remove(l);
+                (this.updatingSectionData).otherData.queueRemove(l); // Paper - avoid copying light data
             }
         }
 
@@ -128,7 +130,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
     protected void enableLightSources(long columnPos, boolean enabled) {
         this.runAllUpdates();
         if (enabled && this.columnsWithSkySources.add(columnPos)) {
-            int i = (this.updatingSectionData).topSections.get(columnPos);
+            int i = (this.updatingSectionData).otherData.getUpdating(columnPos); // Paper - avoid copying light data
             if (i != (this.updatingSectionData).currentLowestY) {
                 long l = SectionPos.asLong(SectionPos.x(columnPos), i - 1, SectionPos.z(columnPos));
                 this.queueAddSource(l);
@@ -152,7 +154,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
             return dataLayer;
         } else {
             long l = SectionPos.offset(sectionPos, Direction.UP);
-            int i = (this.updatingSectionData).topSections.get(SectionPos.getZeroNode(sectionPos));
+            int i = (this.updatingSectionData).otherData.getUpdating(SectionPos.getZeroNode(sectionPos)); // Paper - avoid copying light data
             if (i != (this.updatingSectionData).currentLowestY && SectionPos.y(l) < i) {
                 DataLayer dataLayer2;
                 while((dataLayer2 = this.getDataLayer(l, true)) == null) {
@@ -275,7 +277,7 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
 
     protected boolean isAboveData(long sectionPos) {
         long l = SectionPos.getZeroNode(sectionPos);
-        int i = (this.updatingSectionData).topSections.get(l);
+        int i = (this.updatingSectionData).otherData.getUpdating(l); // Paper - avoid copying light data
         return i == (this.updatingSectionData).currentLowestY || SectionPos.y(sectionPos) >= i;
     }
 
@@ -286,18 +288,21 @@ public class SkyLightSectionStorage extends LayerLightSectionStorage<SkyLightSec
 
     protected static final class SkyDataLayerStorageMap extends DataLayerStorageMap<SkyLightSectionStorage.SkyDataLayerStorageMap> {
         int currentLowestY;
-        final Long2IntOpenHashMap topSections;
-
-        public SkyDataLayerStorageMap(Long2ObjectOpenHashMap<DataLayer> arrays, Long2IntOpenHashMap columnToTopSection, int minSectionY) {
-            super(arrays);
-            this.topSections = columnToTopSection;
-            columnToTopSection.defaultReturnValue(minSectionY);
+        private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data
+
+        // Paper start - avoid copying light data
+        public SkyDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object<DataLayer> arrays, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int columnToTopSection, int minSectionY, boolean isVisible) {
+            super(arrays, isVisible);
+            this.otherData = columnToTopSection;
+            otherData.queueDefaultReturnValue(minSectionY);
+            // Paper end
             this.currentLowestY = minSectionY;
         }
 
         @Override
         public SkyLightSectionStorage.SkyDataLayerStorageMap copy() {
-            return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.map.clone(), this.topSections.clone(), this.currentLowestY);
+            this.otherData.performUpdatesLockMap(); // Paper - avoid copying light data
+            return new SkyLightSectionStorage.SkyDataLayerStorageMap(this.data, this.otherData, this.currentLowestY, true); // Paper - avoid copying light data
         }
     }
 }