papermc/Spigot-Server-Patches/0397-incremental-chunk-saving.patch
Shane Freeder 0708fa363b
Updated Upstream (CraftBukkit/Spigot)
Upstream has released updates that appears to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

CraftBukkit Changes:
eb2e6578 SPIGOT-5116: Fix concurrent modification exception inside ChunkMapDistance
989f9b3d SPIGOT-4849: Fix server crash when accessing chunks during chunk load/unload/populate events
f554183c SPIGOT-5171: Don't fire PlayerTeleportEvent if not actually moving
2349feb8 SPIGOT-5163: Cancelling PlayerBucketFillEvent visually removes the targeted block

Spigot Changes:
9a643a6a Remove DataWatcher Locking
2019-07-16 23:09:32 +01:00

169 lines
8 KiB
Diff

From f8f05a94746e3c53cd0829470615d47b0e65d930 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
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 de11a91af..4d3c6c6b4 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -489,4 +489,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 5bf781bb6..e2a48695d 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<Block> o;
private TickList<FluidType> 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 d6c99ce89..2b99fdc63 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<TickTas
public static int currentTick = 0; // Paper - Further improve tick loop
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
+ public boolean serverAutoSave = false; // Paper
public File bukkitDataPackFolder;
public CommandDispatcher vanillaCommandDispatcher;
private boolean forceTicks;
@@ -1075,14 +1076,28 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
this.serverPing.b().a(agameprofile);
}
- if (autosavePeriod > 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 dee926212..a3e989f2b 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -318,15 +318,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 5eeec7be7..c646393eb 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -756,8 +756,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]));
}
@@ -766,6 +767,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);
@@ -773,6 +775,7 @@ public class WorldServer extends World {
} // Paper
}
+ if (flag || server.serverAutoSave) { // Paper
// CraftBukkit start - moved from MinecraftServer.saveChunks
// PAIL - rename
WorldServer worldserver1 = this;
@@ -782,6 +785,7 @@ public class WorldServer extends World {
worlddata.c(this.server.getBossBattleCustomData().c());
worldserver1.getDataManager().saveWorldData(worlddata, this.server.getPlayerList().r());
// CraftBukkit end
+ } // Paper
}
protected void k_() throws ExceptionWorldConflict {
--
2.22.0