2018-07-30 06:51:58 +02:00
From 603a10033e83fdc9d8757814dd91d03c03f90d9d Mon Sep 17 00:00:00 2001
2016-09-22 04:12:56 +02:00
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.
2016-12-27 22:11:25 +01:00
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
2018-07-30 06:51:58 +02:00
index 621c585e7e..459c86bce2 100644
2016-12-27 22:11:25 +01:00
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
2018-03-05 02:20:27 +01:00
@@ -251,4 +251,15 @@ public class PaperConfig {
2016-12-27 22:11:25 +01:00
flyingKickPlayerMessage = getString("messages.kick.flying-player", flyingKickPlayerMessage);
flyingKickVehicleMessage = getString("messages.kick.flying-vehicle", flyingKickVehicleMessage);
}
+
+ public static int playerAutoSaveRate = -1;
2018-03-05 02:20:27 +01:00
+ public static int maxPlayerAutoSavePerTick = 10;
2016-12-27 22:11:25 +01:00
+ private static void playerAutoSaveRate() {
+ playerAutoSaveRate = getInt("settings.player-auto-save-rate", -1);
2018-03-05 02:20:27 +01:00
+ 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;
+ }
2016-12-27 22:11:25 +01:00
+ }
}
2016-09-22 04:12:56 +02:00
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
2018-07-30 06:51:58 +02:00
index 1b9eb7f45a..ce848d63e3 100644
2016-09-22 04:12:56 +02:00
--- 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;
2017-05-14 20:05:01 +02:00
2018-05-30 22:31:55 +02:00
@@ -363,4 +364,19 @@ public class PaperWorldConfig {
2016-09-22 04:12:56 +02:00
private void elytraHitWallDamage() {
elytraHitWallDamage = getBoolean("elytra-hit-wall-damage", true);
}
+
+ 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
2018-07-30 06:51:58 +02:00
index 178604c50d..ad8a3acabb 100644
2016-09-22 04:12:56 +02:00
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
2018-07-30 06:51:58 +02:00
@@ -997,11 +997,9 @@ public class Chunk {
2016-09-22 04:12:56 +02:00
if (this.t && this.world.getTime() != this.lastSaved || this.s) {
return true;
}
- } else if (this.t && this.world.getTime() >= this.lastSaved + MinecraftServer.getServer().autosavePeriod * 4) { // Spigot - Only save if we've passed 2 auto save intervals without modification
2016-11-04 06:31:49 +01:00
- return true;
2016-09-22 04:12:56 +02:00
}
2016-11-04 06:31:49 +01:00
-
- return this.s;
+ // This !flag section should say if s(isModified) or t(hasEntities), then check auto save
+ return ((this.s || this.t) && this.world.getTime() >= this.lastSaved + world.paperConfig.autoSavePeriod); // Paper - Make world configurable and incremental
}
2016-09-22 04:12:56 +02:00
2016-11-04 06:31:49 +01:00
public Random a(long i) {
2016-09-22 04:12:56 +02:00
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
2018-07-30 06:51:58 +02:00
index 47159bff3c..db81b4a8cf 100644
2016-09-22 04:12:56 +02:00
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -1,5 +1,6 @@
package net.minecraft.server;
+import com.destroystokyo.paper.PaperConfig;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
2016-11-17 03:23:38 +01:00
@@ -266,7 +267,7 @@ public class ChunkProviderServer implements IChunkProvider {
2017-08-12 23:32:01 +02:00
this.saveChunk(chunk, false); // Spigot
2016-09-22 04:12:56 +02:00
chunk.f(false);
++i;
- if (i == 24 && !flag && false) { // Spigot
+ if (!flag && i >= world.paperConfig.maxAutoSaveChunksPerTick) { // Spigot - // Paper - Incremental Auto Save - cap max per tick
return false;
}
}
2016-12-27 22:11:25 +01:00
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
2018-07-30 06:51:58 +02:00
index 2391adac7f..8b7eb47a28 100644
2016-12-27 22:11:25 +01:00
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
2017-05-31 10:04:52 +02:00
@@ -32,6 +32,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
2016-12-27 22:11:25 +01:00
2017-05-21 06:41:39 +02:00
private static final Logger bV = LogManager.getLogger();
2017-05-28 06:25:17 +02:00
public String locale = null; // PAIL: private -> public // Paper - default to null
2016-12-27 22:11:25 +01:00
+ public long lastSave = MinecraftServer.currentTick; // Paper
public PlayerConnection playerConnection;
public final MinecraftServer server;
public final PlayerInteractManager playerInteractManager;
2016-09-22 04:12:56 +02:00
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
2018-07-30 06:51:58 +02:00
index ab79330791..5c09c6ff7c 100644
2016-09-22 04:12:56 +02:00
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
2017-08-03 16:36:06 +02:00
@@ -119,6 +119,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
2016-09-26 07:50:26 +02:00
public final Thread primaryThread;
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
+ public boolean serverAutoSave = false; // Paper
// CraftBukkit end
2017-01-31 05:33:54 +01:00
// Spigot start
public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant();
2017-08-03 16:36:06 +02:00
@@ -766,22 +767,30 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
2016-09-22 04:12:56 +02:00
this.q.b().a(agameprofile);
}
- if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit
this.methodProfiler.a("save");
2016-12-27 22:11:25 +01:00
- this.v.savePlayers();
2016-09-22 04:12:56 +02:00
+
2016-09-26 07:50:26 +02:00
+ serverAutoSave = (autosavePeriod > 0 && this.ticks % autosavePeriod == 0); // Paper
2016-12-27 22:11:25 +01:00
+ int playerSaveInterval = com.destroystokyo.paper.PaperConfig.playerAutoSaveRate;
+ if (playerSaveInterval < 0) {
+ playerSaveInterval = autosavePeriod;
+ }
+ if (playerSaveInterval > 0) { // CraftBukkit // Paper
+ this.v.savePlayers(playerSaveInterval);
2016-09-22 04:12:56 +02:00
// 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 : worlds) {
- 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.b();
- }
+ //} // Paper - Incremental Auto Saving
this.methodProfiler.a("tallying");
2017-01-31 05:33:54 +01:00
// Spigot start
2016-12-27 22:11:25 +01:00
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
2018-07-30 06:51:58 +02:00
index 950dbdc508..23ed9efbfa 100644
2016-12-27 22:11:25 +01:00
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
2017-07-17 02:36:27 +02:00
@@ -343,6 +343,7 @@ public abstract class PlayerList {
2016-12-27 22:11:25 +01:00
}
protected void savePlayerFile(EntityPlayer entityplayer) {
+ entityplayer.lastSave = MinecraftServer.currentTick; // Paper
this.playerFileData.save(entityplayer);
2017-07-17 02:36:27 +02:00
ServerStatisticManager serverstatisticmanager = (ServerStatisticManager) entityplayer.getStatisticManager(); // CraftBukkit
2016-12-27 22:11:25 +01:00
2018-03-31 11:34:25 +02:00
@@ -1245,13 +1246,25 @@ public abstract class PlayerList {
2016-12-27 22:11:25 +01:00
}
+ // Paper start
public void savePlayers() {
+ savePlayers(null);
+ }
+
+ public void savePlayers(Integer interval) {
+ long now = MinecraftServer.currentTick;
MinecraftTimings.savePlayers.startTiming(); // Paper
2018-03-05 02:20:27 +01:00
+ int numSaved = 0; // Paper
2016-12-27 22:11:25 +01:00
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);
2018-03-05 02:20:27 +01:00
+ if (interval != null && ++numSaved <= com.destroystokyo.paper.PaperConfig.maxPlayerAutoSavePerTick) { break; } // Paper
2016-12-27 22:11:25 +01:00
+ }
}
MinecraftTimings.savePlayers.stopTiming(); // Paper
}
+ // Paper end
public void addWhitelist(GameProfile gameprofile) {
this.whitelist.add(new WhiteListEntry(gameprofile));
2016-09-22 04:12:56 +02:00
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
2018-07-30 06:51:58 +02:00
index ebe397116e..53cea76e21 100644
2016-09-22 04:12:56 +02:00
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
2018-04-18 04:25:50 +02:00
@@ -1053,8 +1053,9 @@ public class WorldServer extends World implements IAsyncTaskHandler {
2016-09-22 04:12:56 +02:00
ChunkProviderServer chunkproviderserver = this.getChunkProviderServer();
if (chunkproviderserver.e()) {
- 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
2016-10-21 22:42:49 +02:00
timings.worldSave.startTiming(); // Paper
+ if (flag || server.serverAutoSave) { // Paper
2016-09-22 04:12:56 +02:00
if (iprogressupdate != null) {
iprogressupdate.a("Saving level");
}
2018-04-18 04:25:50 +02:00
@@ -1063,6 +1064,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
2016-09-26 07:50:26 +02:00
if (iprogressupdate != null) {
iprogressupdate.c("Saving chunks");
}
2016-10-21 22:42:49 +02:00
+ } // Paper
timings.worldSaveChunks.startTiming(); // Paper
chunkproviderserver.a(flag);
2016-09-22 04:12:56 +02:00
--
2018-07-04 09:55:24 +02:00
2.18.0
2016-09-22 04:12:56 +02:00