diff options
Diffstat (limited to 'patches/server/0451-Stop-copy-on-write-operations-for-updating-light-dat.patch')
-rw-r--r-- | patches/server/0451-Stop-copy-on-write-operations-for-updating-light-dat.patch | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/patches/server/0451-Stop-copy-on-write-operations-for-updating-light-dat.patch b/patches/server/0451-Stop-copy-on-write-operations-for-updating-light-dat.patch new file mode 100644 index 0000000000..74e5860e6b --- /dev/null +++ b/patches/server/0451-Stop-copy-on-write-operations-for-updating-light-dat.patch @@ -0,0 +1,297 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +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 + } + } + } |