From fe90f3351f14e18c2f52fd111ca191e0d3b14940 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sun, 9 Jun 2019 03:53:22 +0100 Subject: [PATCH] incremental chunk saving diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java index b854061983..58109e1308 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -494,4 +494,19 @@ public class PaperWorldConfig { keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16); log( "Keep Spawn Loaded Range: " + (keepLoadedRange/16)); } + + public int autoSavePeriod = -1; + private void autoSavePeriod() { + autoSavePeriod = getInt("auto-save-interval", -1); + if (autoSavePeriod > 0) { + log("Auto Save Interval: " +autoSavePeriod + " (" + (autoSavePeriod / 20) + "s)"); + } else if (autoSavePeriod < 0) { + autoSavePeriod = net.minecraft.server.MinecraftServer.getServer().autosavePeriod; + } + } + + public int maxAutoSaveChunksPerTick = 24; + private void maxAutoSaveChunksPerTick() { + maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24); + } } diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java index 5bf781bb63..e2a48695df 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -42,7 +42,7 @@ public class Chunk implements IChunkAccess { private TickList o; private TickList p; private boolean q; - private long lastSaved; + public long lastSaved; // Paper private volatile boolean s; private long t; @Nullable diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index b401ff7695..485725c0ae 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -155,6 +155,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; + public boolean serverAutoSave = false; // Paper public File bukkitDataPackFolder; public CommandDispatcher vanillaCommandDispatcher; private boolean forceTicks; @@ -1071,14 +1072,28 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit + //if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit // Paper - move down MinecraftServer.LOGGER.debug("Autosave started"); + serverAutoSave = (autosavePeriod > 0 && this.ticks % autosavePeriod == 0); // Paper this.methodProfiler.enter("save"); + if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // Paper this.playerList.savePlayers(); - this.saveChunks(true, false, false); + }// Paper + // Paper start + for (WorldServer world : getWorlds()) { + if (world.paperConfig.autoSavePeriod > 0) { + try { + world.save(null, false, world.isSavingDisabled()); + } catch (ExceptionWorldConflict exceptionWorldConflict) { + MinecraftServer.LOGGER.warn(exceptionWorldConflict.getMessage()); + } + } + } + // Paper end + this.methodProfiler.exit(); MinecraftServer.LOGGER.debug("Autosave finished"); - } + //} // Paper this.methodProfiler.enter("snooper"); if (((DedicatedServer) this).getDedicatedServerProperties().snooperEnabled && !this.snooper.d() && this.ticks > 100) { // Spigot diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java index d85220b66c..c4ad039ffd 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -293,15 +293,32 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { }); PlayerChunkMap.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.x.getName()); } else { - this.visibleChunks.values().stream().filter(PlayerChunk::hasBeenLoaded).forEach((playerchunk) -> { + // Paper start + int savedThisTick = 0; + for (PlayerChunk playerchunk : this.visibleChunks.values()) { + if (!playerchunk.hasBeenLoaded()) continue; + // Paper end IChunkAccess ichunkaccess = (IChunkAccess) playerchunk.getChunkSave().getNow(null); // CraftBukkit - decompile error if (ichunkaccess instanceof ProtoChunkExtension || ichunkaccess instanceof Chunk) { - this.saveChunk(ichunkaccess); + // paper start + boolean shouldSave = true; + + if (ichunkaccess instanceof Chunk) { + shouldSave = ((Chunk) ichunkaccess).lastSaved + world.paperConfig.autoSavePeriod <= world.getTime(); + } + + if (shouldSave && this.saveChunk(ichunkaccess)) { + ++savedThisTick; playerchunk.m(); } - }); + if (savedThisTick >= world.paperConfig.maxAutoSaveChunksPerTick) { + return; + } + } + }; + // paper end } } diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java index d086af67f9..52523789b2 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -755,8 +755,9 @@ public class WorldServer extends World { ChunkProviderServer chunkproviderserver = this.getChunkProvider(); if (!flag1) { - org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit + if (flag || server.serverAutoSave) org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit // Paper - full saves only try (co.aikar.timings.Timing ignored = timings.worldSave.startTiming()) { // Paper + if (flag || server.serverAutoSave) { // Paper if (iprogressupdate != null) { iprogressupdate.a(new ChatMessage("menu.savingLevel", new Object[0])); } @@ -765,6 +766,7 @@ public class WorldServer extends World { if (iprogressupdate != null) { iprogressupdate.c(new ChatMessage("menu.savingChunks", new Object[0])); } + } // Paper timings.worldSaveChunks.startTiming(); // Paper chunkproviderserver.save(flag); -- 2.22.0