Paper/Spigot-Server-Patches/0135-Auto-Save-Improvements.patch
Zach Brown a2ad49b22f
Update upstream BD/B/CB/S
Note to other developers: This commit may require you to wipe your
workspace as a result of the changes to BD.

--- work/BuildData
Submodule work/BuildData f527a8ff..d56672db:
  > Mappings Update

--- work/Bukkit
Submodule work/Bukkit 0c1d258bb..db06c80d7:
  > Add list of entities to EntityTransformEvent
  > SPIGOT-4347: Add API to allow storing arbitrary values on ItemStacks

---work/CraftBukkit
Submodule work/CraftBukkit 6a398ac44..068dab5be:
  > Enable optional source JAR shading via profile shadeSourcesJar
  > Use ImmutableList rather than AbstractList for CraftMetaBook
  > Fix setRecipes(List) not setting Knowledge Book recipes.
  > Mappings Update
  > Add list of entities to EntityTransformEvent & move die calls
  > SPIGOT-4347: Add API to allow storing arbitrary values on ItemStacks
  > Add Vanilla help to default permissions

--- work/Spigot
Submodule work/Spigot a1f2566f6..e769fe4d9:
  > Mappings Update
  > Rebuild patches
2018-12-08 05:09:55 -05:00

235 lines
12 KiB
Diff

From f3f73f4392a3801bfe4b3de63f2611b5336e4a4b Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 19 Sep 2016 23:16:39 -0400
Subject: [PATCH] Auto Save Improvements
Makes Auto Save Rate setting configurable per-world. If the auto save rate is left -1, the global bukkit.yml value will be used.
Process auto save every tick instead of once per auto tick interval, so that chunk saves will distribute over many ticks instead of all at once.
Re-introduce a cap per tick for auto save (Spigot disabled the vanilla cap) and make it configurable.
Adds incremental player auto saving too
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index c278ac98d..ae3d0f8f7 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -269,4 +269,15 @@ public class PaperConfig {
flyingKickPlayerMessage = getString("messages.kick.flying-player", flyingKickPlayerMessage);
flyingKickVehicleMessage = getString("messages.kick.flying-vehicle", flyingKickVehicleMessage);
}
+
+ public static int playerAutoSaveRate = -1;
+ public static int maxPlayerAutoSavePerTick = 10;
+ private static void playerAutoSaveRate() {
+ playerAutoSaveRate = getInt("settings.player-auto-save-rate", -1);
+ maxPlayerAutoSavePerTick = getInt("settings.max-player-auto-save-per-tick", -1);
+ if (maxPlayerAutoSavePerTick == -1) { // -1 Automatic / "Recommended"
+ // 10 should be safe for everyone unless your mass spamming player auto save
+ maxPlayerAutoSavePerTick = (playerAutoSaveRate == -1 || playerAutoSaveRate > 100) ? 10 : 20;
+ }
+ }
}
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 0cd15c17e..c43152f45 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -2,6 +2,7 @@ package com.destroystokyo.paper;
import java.util.List;
+import net.minecraft.server.MinecraftServer;
import org.bukkit.configuration.file.YamlConfiguration;
import org.spigotmc.SpigotWorldConfig;
@@ -310,4 +311,19 @@ public class PaperWorldConfig {
private void skipEntityTickingInChunksScheduledForUnload() {
skipEntityTickingInChunksScheduledForUnload = getBoolean("skip-entity-ticking-in-chunks-scheduled-for-unload", skipEntityTickingInChunksScheduledForUnload);
}
+
+ 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 = 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 9328c21cd..aa2ea7838 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -49,9 +49,9 @@ public class Chunk implements IChunkAccess {
private final TickList<Block> s;
private final TickList<FluidType> t;
private boolean u;
- private boolean v;
+ private boolean v;public boolean hasEntities() { return v; } // Paper - OBFHELPER
private long lastSaved;
- private boolean x;
+ private boolean x; public boolean isModified() { return x; } // Paper - OBFHELPER
private int y;
private long z;
private int A;
@@ -1059,11 +1059,11 @@ public class Chunk implements IChunkAccess {
if (this.v && this.world.getTime() != this.lastSaved || this.x) {
return true;
}
- } else if (this.v && this.world.getTime() >= this.lastSaved + MinecraftServer.getServer().autosavePeriod * 4) { // Spigot - Only save if we've passed 2 auto save intervals without modification
- return true;
}
-
- return this.x;
+ // Paper start - Make world configurable and incremental
+ // This !flag section should say if isModified or hasEntities, then check auto save
+ return ((isModified() || hasEntities()) && this.world.getTime() >= this.lastSaved + world.paperConfig.autoSavePeriod);
+ // Paper end
}
public boolean isEmpty() {
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 516a583a8..27bed54d2 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -243,7 +243,7 @@ public class ChunkProviderServer implements IChunkProvider {
this.saveChunk(chunk, false); // Spigot
chunk.a(false);
++i;
- if (i == 24 && !flag && false) { // Spigot
+ if (!flag && i >= world.paperConfig.maxAutoSaveChunksPerTick) { // Spigot - // Paper - Incremental Auto Save - cap max
return false;
}
}
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index 3e4c80e0f..8506fad6f 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -37,6 +37,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
private static final Logger cc = LogManager.getLogger();
public String locale = null; // CraftBukkit - lowercase // Paper - default to null
+ public long lastSave = MinecraftServer.currentTick; // Paper
public PlayerConnection playerConnection;
public final MinecraftServer server;
public final PlayerInteractManager playerInteractManager;
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index bdf4aed1a..acdfb0e1e 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -148,6 +148,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
public org.bukkit.command.RemoteConsoleCommandSender remoteConsole;
public ConsoleReader reader;
public static int currentTick = 0; // Paper - Further improve tick loop
+ public boolean serverAutoSave = false; // Paper
public final Thread primaryThread;
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
@@ -942,22 +943,30 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
this.m.b().a(agameprofile);
}
- if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit
this.methodProfiler.a("save");
- this.s.savePlayers();
+
+ serverAutoSave = (autosavePeriod > 0 && this.ticks % autosavePeriod == 0); // Paper
+ int playerSaveInterval = com.destroystokyo.paper.PaperConfig.playerAutoSaveRate;
+ if (playerSaveInterval < 0) {
+ playerSaveInterval = autosavePeriod;
+ }
+ if (playerSaveInterval > 0) { // CraftBukkit // Paper
+ this.s.savePlayers(playerSaveInterval);
// Spigot Start
+ } // Paper - Incremental Auto Saving
+
// We replace this with saving each individual world as this.saveChunks(...) is broken,
// and causes the main thread to sleep for random amounts of time depending on chunk activity
// Also pass flag to only save modified chunks
server.playerCommandState = true;
for (World world : getWorlds()) {
- world.getWorld().save(false);
+ if (world.paperConfig.autoSavePeriod > 0) world.getWorld().save(false); // Paper - Incremental / Configurable Auto Saving
}
server.playerCommandState = false;
// this.saveChunks(true);
// Spigot End
this.methodProfiler.e();
- }
+ //} // Paper - Incremental Auto Saving
this.methodProfiler.a("snooper");
if (getSnooperEnabled() && !this.i.d() && this.ticks > 100) { // Spigot
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index 143c7c1be..1259ec9d6 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -342,6 +342,7 @@ public abstract class PlayerList {
protected void savePlayerFile(EntityPlayer entityplayer) {
if (!entityplayer.getBukkitEntity().isPersistent()) return; // CraftBukkit
+ entityplayer.lastSave = MinecraftServer.currentTick; // Paper
this.playerFileData.save(entityplayer);
ServerStatisticManager serverstatisticmanager = (ServerStatisticManager) entityplayer.getStatisticManager(); // CraftBukkit
@@ -1208,13 +1209,25 @@ public abstract class PlayerList {
}
+ // Paper start
public void savePlayers() {
+ savePlayers(null);
+ }
+
+ public void savePlayers(Integer interval) {
+ long now = MinecraftServer.currentTick;
MinecraftTimings.savePlayers.startTiming(); // Paper
+ int numSaved = 0; // Paper
for (int i = 0; i < this.players.size(); ++i) {
- this.savePlayerFile((EntityPlayer) this.players.get(i));
+ EntityPlayer entityplayer = this.players.get(i);
+ if (interval == null || now - entityplayer.lastSave >= interval) {
+ this.savePlayerFile(entityplayer);
+ if (interval != null && ++numSaved <= com.destroystokyo.paper.PaperConfig.maxPlayerAutoSavePerTick) { break; } // Paper
+ }
}
MinecraftTimings.savePlayers.stopTiming(); // Paper
}
+ // Paper end
public WhiteList getWhitelist() {
return this.whitelist;
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index b37b284a5..6a5a7d1e0 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -872,8 +872,9 @@ public class WorldServer extends World implements IAsyncTaskHandler {
ChunkProviderServer chunkproviderserver = this.getChunkProviderServer();
if (chunkproviderserver.d()) {
- org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit
+ if (flag) org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit // Paper - Incremental Auto Saving - Only fire event on full save
timings.worldSave.startTiming(); // Paper
+ if (flag || server.serverAutoSave) { // Paper
if (iprogressupdate != null) {
iprogressupdate.a(new ChatMessage("menu.savingLevel", new Object[0]));
}
@@ -882,6 +883,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
if (iprogressupdate != null) {
iprogressupdate.c(new ChatMessage("menu.savingChunks", new Object[0]));
}
+ } // Paper
timings.worldSaveChunks.startTiming(); // Paper
chunkproviderserver.a(flag);
--
2.19.2