2018-09-23 05:30:54 +02:00
From 4aee3a67204e2cca9bd24f8b891807f57c8d7110 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-09-08 05:49:37 +02:00
index aa0e3c757d..c1845d6811 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-07-24 02:24:44 +02:00
@@ -255,4 +255,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-09-23 04:48:30 +02:00
index 62268d34d1..2399777c5e 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-09-23 04:48:30 +02:00
@@ -308,4 +309,19 @@ public class PaperWorldConfig {
2018-07-16 22:08:09 +02:00
private void skipEntityTickingInChunksScheduledForUnload() {
skipEntityTickingInChunksScheduledForUnload = getBoolean("skip-entity-ticking-in-chunks-scheduled-for-unload", skipEntityTickingInChunksScheduledForUnload);
2016-09-22 04:12:56 +02:00
}
+
+ 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
Improve Light Queue and force enable it for all
There is no reason for the light queue to even be an option. This
enables the light queue for everyone.
This also improves the "can we still tick" time logic to always
check before running a light operation.
previously, we always executed at least 10 on the first world
(but not other worlds...), but we are seeing light take up some
heavy time, so improving that for now.
I've now also improved recheck gaps logic to happen at the end of all single block updates
This also prevents multiple gap checks, as previously if a tick skipped
the gaps check, the next tick would end up re-adding the entry again,
resulting in multiple gap checks.
This now just sets a marker "We need to recheck gaps" and will only occur
once.
This also should reduce chunk loads, as previously, we checked if
the neighbor chunks were loaded for the gap check, however those
neighbor chunks might of unloaded before the light queue operation
actually ran. Now, the neighbor chunk is done when the gap check
is being done, so it should avoid loading chunks.
Fixes #1466
Fixes #1431
2018-09-22 17:46:31 +02:00
index 7f1d0b39cf..5285bfb409 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-08-26 20:11:49 +02:00
@@ -50,9 +50,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
2018-07-21 22:03:10 +02:00
private long lastSaved;
2018-08-26 20:11:49 +02:00
- private boolean x;
+ private boolean x; public boolean isModified() { return x; } // Paper - OBFHELPER
private int y;
private long z;
private int A;
Improve Light Queue and force enable it for all
There is no reason for the light queue to even be an option. This
enables the light queue for everyone.
This also improves the "can we still tick" time logic to always
check before running a light operation.
previously, we always executed at least 10 on the first world
(but not other worlds...), but we are seeing light take up some
heavy time, so improving that for now.
I've now also improved recheck gaps logic to happen at the end of all single block updates
This also prevents multiple gap checks, as previously if a tick skipped
the gaps check, the next tick would end up re-adding the entry again,
resulting in multiple gap checks.
This now just sets a marker "We need to recheck gaps" and will only occur
once.
This also should reduce chunk loads, as previously, we checked if
the neighbor chunks were loaded for the gap check, however those
neighbor chunks might of unloaded before the light queue operation
actually ran. Now, the neighbor chunk is done when the gap check
is being done, so it should avoid loading chunks.
Fixes #1466
Fixes #1431
2018-09-22 17:46:31 +02:00
@@ -1022,11 +1022,11 @@ public class Chunk implements IChunkAccess {
2018-08-26 20:11:49 +02:00
if (this.v && this.world.getTime() != this.lastSaved || this.x) {
2016-09-22 04:12:56 +02:00
return true;
}
2018-08-26 20:11:49 +02:00
- } 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
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
-
2018-08-26 20:11:49 +02:00
- return this.x;
2018-07-21 22:03:10 +02:00
+ // 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
2016-11-04 06:31:49 +01:00
}
2016-09-22 04:12:56 +02:00
2018-07-16 22:08:09 +02:00
public boolean isEmpty() {
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-09-18 04:32:37 +02:00
index 9739288b53..a35eac043c 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
2018-08-27 06:15:12 +02:00
@@ -241,7 +241,7 @@ public class ChunkProviderServer implements IChunkProvider {
2018-08-26 20:11:49 +02:00
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;
}
2016-09-22 04:12:56 +02:00
}
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-09-18 04:32:37 +02:00
index 3d83900298..690cff8828 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
2018-08-26 20:11:49 +02:00
@@ -37,6 +37,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
2018-07-16 22:08:09 +02:00
private static final Logger cc = LogManager.getLogger();
public String locale = null; // CraftBukkit - lowercase // 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-09-18 04:32:37 +02:00
index 04d8c108b4..a547ee5ca1 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
2018-09-08 05:49:37 +02:00
@@ -148,6 +148,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
2018-07-21 22:03:10 +02:00
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;
2016-09-26 07:50:26 +02:00
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
2018-09-18 04:32:37 +02:00
@@ -942,22 +943,30 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
2018-08-26 20:11:49 +02:00
this.m.b().a(agameprofile);
2016-09-22 04:12:56 +02:00
}
- if (autosavePeriod > 0 && this.ticks % autosavePeriod == 0) { // CraftBukkit
this.methodProfiler.a("save");
2018-07-16 22:08:09 +02:00
- this.s.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
2018-07-16 22:08:09 +02:00
+ this.s.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;
2018-08-26 20:11:49 +02:00
for (World world : getWorlds()) {
2016-09-22 04:12:56 +02:00
- 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
2018-07-16 22:08:09 +02:00
this.methodProfiler.e();
2016-09-22 04:12:56 +02:00
- }
+ //} // Paper - Incremental Auto Saving
2018-07-16 22:08:09 +02:00
this.methodProfiler.a("snooper");
2018-08-26 20:11:49 +02:00
if (getSnooperEnabled() && !this.i.d() && this.ticks > 100) { // Spigot
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-09-08 05:49:37 +02:00
index 02dbb8c6c3..73d72ef7e3 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
2018-07-19 06:42:43 +02:00
@@ -341,6 +341,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-08-26 20:11:49 +02:00
@@ -1207,13 +1208,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
2018-07-16 22:08:09 +02:00
public WhiteList getWhitelist() {
return this.whitelist;
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-09-18 04:32:37 +02:00
index c5201697d5..ca2e027cda 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-07-16 22:08:09 +02:00
@@ -872,8 +872,9 @@ public class WorldServer extends World implements IAsyncTaskHandler {
2016-09-22 04:12:56 +02:00
ChunkProviderServer chunkproviderserver = this.getChunkProviderServer();
2018-08-26 20:11:49 +02:00
if (chunkproviderserver.d()) {
2016-09-22 04:12:56 +02:00
- 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) {
2018-07-16 22:08:09 +02:00
iprogressupdate.a(new ChatMessage("menu.savingLevel", new Object[0]));
2016-09-22 04:12:56 +02:00
}
2018-07-16 22:08:09 +02:00
@@ -882,6 +883,7 @@ public class WorldServer extends World implements IAsyncTaskHandler {
2016-09-26 07:50:26 +02:00
if (iprogressupdate != null) {
2018-07-16 22:08:09 +02:00
iprogressupdate.c(new ChatMessage("menu.savingChunks", new Object[0]));
2016-09-26 07:50:26 +02:00
}
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-09-18 04:32:37 +02:00
2.19.0
2016-09-22 04:12:56 +02:00