From 4b2f4cbebbb06bcaf775f8b7a21930dad30cf1ab Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 13 Jun 2021 22:34:40 -0700 Subject: [PATCH] Add back incremental chunk saving patch --- .../0446-incremental-chunk-saving.patch} | 185 ++++++++++-------- 1 file changed, 101 insertions(+), 84 deletions(-) rename patches/{removed/1.17/0363-incremental-chunk-saving.patch => server/0446-incremental-chunk-saving.patch} (64%) diff --git a/patches/removed/1.17/0363-incremental-chunk-saving.patch b/patches/server/0446-incremental-chunk-saving.patch similarity index 64% rename from patches/removed/1.17/0363-incremental-chunk-saving.patch rename to patches/server/0446-incremental-chunk-saving.patch index 70420b4593..8856801d1f 100644 --- a/patches/removed/1.17/0363-incremental-chunk-saving.patch +++ b/patches/server/0446-incremental-chunk-saving.patch @@ -2,17 +2,16 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sun, 9 Jun 2019 03:53:22 +0100 Subject: [PATCH] incremental chunk saving -1.17: saved for MM + diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index ffe9b1a63d78925e1d77b9e730aef42fed6d58fa..1278d09f70c1e97607ef20d87a178dc252c7f723 100644 +index 3bc6329d3ea48966cb99e792f9b35e2d2d71a34b..ec51a9e19670888584e5324a57a47aa9c676d423 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -446,4 +446,19 @@ public class PaperWorldConfig { - keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); +@@ -47,6 +47,21 @@ public class PaperWorldConfig { log( "Keep Spawn Loaded Range: " + (keepLoadedRange/16)); } -+ + + public int autoSavePeriod = -1; + private void autoSavePeriod() { + autoSavePeriod = getInt("auto-save-interval", -1); @@ -27,64 +26,65 @@ index ffe9b1a63d78925e1d77b9e730aef42fed6d58fa..1278d09f70c1e97607ef20d87a178dc2 + private void maxAutoSaveChunksPerTick() { + maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24); + } - } ++ + private boolean getBoolean(String path, boolean def) { + config.addDefault("world-settings.default." + path, def); + return config.getBoolean("world-settings." + worldName + "." + path, config.getBoolean("world-settings.default." + path)); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0efe7024493f96bb54e7d8c1ea7b233a1b481a04..aab1a055c065d1f1a92461e4442ec2cdd8e0b347 100644 +index 11dbe48c8a8c29cd28d725c43505e326a6e626ff..363dcebb3b2d5a2512776a191f6716ed3d0e8aff 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -261,6 +261,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; + public boolean serverAutoSave = false; // Paper public Commands vanillaCommandDispatcher; - private boolean forceTicks; + public boolean forceTicks; // Paper // CraftBukkit end -@@ -1256,14 +1257,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && this.tickCount % autosavePeriod == 0) { // CraftBukkit +- if (this.autosavePeriod > 0 && this.tickCount % this.autosavePeriod == 0) { // CraftBukkit - MinecraftServer.LOGGER.debug("Autosave started"); -+ //if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit // Paper - move down -+ //MinecraftServer.LOGGER.debug("Autosave started"); // Paper -+ serverAutoSave = (autosavePeriod > 0 && this.tickCount % autosavePeriod == 0); // Paper ++ // if (this.autosavePeriod > 0 && this.tickCount % this.autosavePeriod == 0) { // CraftBukkit // Paper - move down ++ // MinecraftServer.LOGGER.debug("Autosave started"); // Paper ++ serverAutoSave = (autosavePeriod > 0 && this.tickCount % autosavePeriod == 0); // Paper this.profiler.push("save"); -+ if (autosavePeriod > 0 && this.tickCount % autosavePeriod == 0) { // Paper ++ if (this.autosavePeriod > 0 && this.tickCount % this.autosavePeriod == 0) { // Paper - moved from above this.playerList.saveAll(); - this.saveAllChunks(true, false, false); -+ }// Paper -+ // Paper start -+ for (ServerLevel world : getAllLevels()) { -+ if (world.paperConfig.autoSavePeriod > 0) { -+ world.saveIncrementally(serverAutoSave); -+ } -+ } -+ // Paper end -+ - this.profiler.pop(); +- this.profiler.pop(); - MinecraftServer.LOGGER.debug("Autosave finished"); -- } -+ //MinecraftServer.LOGGER.debug("Autosave finished"); // Paper ++ // this.saveAllChunks(true, false, false); // Paper - saved incrementally below ++ } // Paper start ++ for (ServerLevel level : this.getAllLevels()) { ++ if (level.paperConfig.autoSavePeriod > 0) { ++ level.saveIncrementally(this.serverAutoSave); ++ } + } ++ // Paper end ++ this.profiler.pop(); ++ // MinecraftServer.LOGGER.debug("Autosave finished"); // Paper + //} // Paper this.profiler.push("snooper"); if (((DedicatedServer) this).getProperties().snooperEnabled && !this.snooper.isStarted() && this.tickCount > 100) { // Spigot diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 7010e0a970462d2b2e1b5696a1a49dba9ea60935..491a9e78fdcec8c211499e8f48cceb829f1e5c8b 100644 +index 969b0c9cf6d7eb2055d3b804f25a3cbc161ceaea..1f67c9c5f7161ea687983e7ae0ec7d259da9acd3 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -66,6 +66,9 @@ public class ChunkHolder { - - private final ChunkMap chunkMap; // Paper - +@@ -111,6 +111,8 @@ public class ChunkHolder { + this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); + } + // Paper end - optimise isOutsideOfRange + long lastAutoSaveTime; // Paper - incremental autosave + long inactiveTimeStart; // Paper - incremental autosave -+ - public ChunkHolder(ChunkPos pos, int level, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { + + public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size()); - this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -@@ -421,7 +424,19 @@ public class ChunkHolder { +@@ -533,7 +535,19 @@ public class ChunkHolder { boolean flag2 = playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER); boolean flag3 = playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER); @@ -102,14 +102,14 @@ index 7010e0a970462d2b2e1b5696a1a49dba9ea60935..491a9e78fdcec8c211499e8f48cceb82 + } + // Paper end if (!flag2 && flag3) { - // Paper start - cache ticking ready status - int expectCreateCount = ++this.fullChunkCreateCount; -@@ -541,8 +556,32 @@ public class ChunkHolder { + int expectCreateCount = ++this.fullChunkCreateCount; // Paper + this.fullChunkFuture = chunkStorage.prepareAccessibleChunk(this); +@@ -654,9 +668,33 @@ public class ChunkHolder { } public void refreshAccessibility() { + boolean prev = this.wasAccessibleSinceLastSave; // Paper -+ this.wasAccessibleSinceLastSave = getFullChunkStatus(this.ticketLevel).isOrAfter(ChunkHolder.FullChunkStatus.BORDER); + this.wasAccessibleSinceLastSave = ChunkHolder.getFullChunkStatus(this.ticketLevel).isOrAfter(ChunkHolder.FullChunkStatus.BORDER); + // Paper start - incremental autosave + if (prev != this.wasAccessibleSinceLastSave) { + if (this.wasAccessibleSinceLastSave) { @@ -126,22 +126,23 @@ index 7010e0a970462d2b2e1b5696a1a49dba9ea60935..491a9e78fdcec8c211499e8f48cceb82 + } + } + // Paper end -+ } -+ + } + + // Paper start - incremental autosave + public boolean setHasBeenLoaded() { - this.wasAccessibleSinceLastSave = getFullChunkStatus(this.ticketLevel).isOrAfter(ChunkHolder.FullChunkStatus.BORDER); ++ this.wasAccessibleSinceLastSave = getFullChunkStatus(this.ticketLevel).isOrAfter(ChunkHolder.FullChunkStatus.BORDER); + return this.wasAccessibleSinceLastSave; - } ++ } + // Paper end - - public void replaceProtoChunk(ImposterProtoChunk protochunkextension) { ++ + public void replaceProtoChunk(ImposterProtoChunk chunk) { for (int i = 0; i < this.futures.length(); ++i) { + CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 0aac29de933c84c34cb24e204e8fcc7010060d8f..cfec04e12dfaeb8852dc129a6a7e68c61dac54b6 100644 +index d8f99f7f5ca0e1dbbb9b760af3a4b4f9c52ef6c7..5a5e9188f55405c8a2646891c348d544d33eb940 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -91,6 +91,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureMana +@@ -93,6 +93,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureMana import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.phys.Vec3; @@ -149,7 +150,7 @@ index 0aac29de933c84c34cb24e204e8fcc7010060d8f..cfec04e12dfaeb8852dc129a6a7e68c6 import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -@@ -378,6 +379,64 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -744,6 +745,64 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -212,30 +213,37 @@ index 0aac29de933c84c34cb24e204e8fcc7010060d8f..cfec04e12dfaeb8852dc129a6a7e68c6 + // Paper end + protected void saveAllChunks(boolean flush) { + Long2ObjectLinkedOpenHashMap visibleChunks = this.getVisibleChunks(); // Paper remove clone of visible Chunks unless saving off main thread (watchdog kill) if (flush) { - List list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); -@@ -488,6 +547,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -883,6 +942,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + asyncSaveData, chunk); + + chunk.setUnsaved(false); ++ chunk.setLastSaved(this.level.getGameTime()); // Paper - track last saved time + } + // Paper end + +@@ -905,6 +965,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.level.unload(chunk); } -+ this.autoSaveQueue.remove(playerchunk); // Paper ++ this.autoSaveQueue.remove(holder); // Paper - this.lightEngine.updateChunkStatus(ichunkaccess.getPos()); - this.lightEngine.tryScheduleUpdate(); -@@ -680,6 +740,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - playerchunk.replaceProtoChunk(new ImposterProtoChunk(chunk)); - } + // Paper start - async chunk saving + try { +@@ -1231,6 +1292,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (!chunk.isUnsaved()) { + return false; + } else { ++ chunk.setLastSaved(this.level.getGameTime()); // Paper - track save time + chunk.setUnsaved(false); + ChunkPos chunkcoordintpair = chunk.getPos(); -+ chunk.setLastSaveTime(this.level.getGameTime() - 1); // Paper - avoid autosaving newly generated/loaded chunks -+ - chunk.setFullStatus(() -> { - return ChunkHolder.getFullChunkStatus(playerchunk.getTicketLevel()); - }); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 1e8ac0110badbf2d1c2336168c3e11991667c782..c1aa40c01a80a8870478193b8cd7354b0d71045c 100644 +index 3faa808f41f057a9956c697ec1323330f5920b86..7ab28e9bd3f785838b7fa4ac5811c0e71cddcb61 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -558,6 +558,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -671,6 +671,15 @@ public class ServerChunkCache extends ChunkSource { } // Paper - Timings } @@ -252,10 +260,10 @@ index 1e8ac0110badbf2d1c2336168c3e11991667c782..c1aa40c01a80a8870478193b8cd7354b public void close() throws IOException { // CraftBukkit start diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index b2ddf145ae9f581ec6820deb9cb6a98be87658d7..fd7ee4badb383ffb4347d62c00ea2dfa3d76fd12 100644 +index fd3159f7767faaa55ed49eba237e30a2dbd4fa92..9fb7345a8c3985aa3e0f4575d680b82379d2cc5a 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -882,6 +882,38 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl +@@ -1014,6 +1014,38 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos); } @@ -267,14 +275,14 @@ index b2ddf145ae9f581ec6820deb9cb6a98be87658d7..fd7ee4badb383ffb4347d62c00ea2dfa + org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); + } + -+ try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { ++ try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) { + if (doFull) { -+ this.saveData(); ++ this.saveLevelData(); + } + -+ timings.worldSaveChunks.startTiming(); // Paper ++ this.timings.worldSaveChunks.startTiming(); // Paper + if (!this.noSave()) chunkproviderserver.saveIncrementally(); -+ timings.worldSaveChunks.stopTiming(); // Paper ++ this.timings.worldSaveChunks.stopTiming(); // Paper + + + // Copied from save() @@ -282,9 +290,9 @@ index b2ddf145ae9f581ec6820deb9cb6a98be87658d7..fd7ee4badb383ffb4347d62c00ea2dfa + if (doFull) { // Paper + ServerLevel worldserver1 = this; + -+ worldDataServer.setWorldBorder(worldserver1.getWorldBorder().createSettings()); -+ worldDataServer.setCustomBossEvents(this.server.getCustomBossEvents().save()); -+ convertable.saveDataTag(this.server.registryHolder, this.worldDataServer, this.server.getPlayerList().getSingleplayerData()); ++ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings()); ++ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save()); ++ this.convertable.saveDataTag(this.server.registryHolder, this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); + } + // CraftBukkit end + } @@ -294,24 +302,33 @@ index b2ddf145ae9f581ec6820deb9cb6a98be87658d7..fd7ee4badb383ffb4347d62c00ea2dfa public void save(@Nullable ProgressListener progressListener, boolean flush, boolean flag1) { ServerChunkCache chunkproviderserver = this.getChunkSource(); -@@ -912,6 +944,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl - // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +index c0075d226331f32e470dae5bf1ce8d79e8b263dc..8ba782511b0a6c7859cbcf910ad742cbb9f599e5 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +@@ -29,6 +29,7 @@ public interface ChunkAccess extends BlockGetter, FeatureAccess { + return GameEventDispatcher.NOOP; } -+ private void saveData() { this.saveLevelData(); } // Paper - OBFHELPER - private void saveLevelData() { - if (this.dragonFight != null) { - this.worldDataServer.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit ++ default void setLastSaved(long ticks) {} + // Paper start + default boolean generateFlatBedrock() { + if (this instanceof ProtoChunk) { diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 55872a17060a35b727a597bc414fecec3ada3515..419b4bf0549d798d52d73fbbd9de59313fc05eb1 100644 +index a63dc77db41dab79f03ef7384da55c1cdeca5d98..efb9c6fef915b43c9dd4468ead52aa36ea9e7ef3 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -80,7 +80,7 @@ public class LevelChunk implements ChunkAccess { +@@ -108,6 +108,13 @@ public class LevelChunk implements ChunkAccess { + private final ShortList[] postProcessing; private TickList blockTicks; private TickList liquidTicks; - private boolean lastSaveHadEntities; -- private long lastSaveTime; -+ public long lastSaveTime; // Paper ++ // Paper start - track last save time ++ public long lastSaveTime; ++ @Override ++ public void setLastSaved(long ticks) { ++ this.lastSaveTime = ticks; ++ } ++ // Paper end private volatile boolean unsaved; private long inhabitedTime; @Nullable