2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: miclebrick <miclebrick@outlook.com>
Date: Wed, 8 Aug 2018 15:30:52 -0400
Subject: [PATCH] Add Early Warning Feature to WatchDog
Detect when the server has been hung for a long duration, and start printing
thread dumps at an interval until the point of crash.
This will help diagnose what was going on in that time before the crash.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-01-24 13:07:40 +01:00
index 1f5f8c7398e974fc8771265b1bc27f68065f944a..bfd405397f685021fdba7780e3709e29ccc89bec 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-01-24 13:07:40 +01:00
@@ -1040,6 +1040,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2023-03-14 19:59:51 +01:00
this.status = this.buildServerStatus();
2021-06-11 14:02:28 +02:00
2022-06-07 23:45:11 +02:00
// Spigot start
2022-06-08 06:22:42 +02:00
+ org.spigotmc.WatchdogThread.hasStarted = true; // Paper
2023-10-27 01:34:58 +02:00
Arrays.fill( this.recentTps, 20 );
2024-01-24 11:45:17 +01:00
long tickSection = Util.getMillis(), tickCount = 1;
2023-12-05 23:12:48 +01:00
while (this.running) {
2022-06-09 10:51:45 +02:00
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
2024-01-24 13:07:40 +01:00
index 6aede562955799fae90a1234b6300ba3a91ba2f2..333647f4328c29afffdc2b0de5abeec731959c59 100644
2022-06-09 10:51:45 +02:00
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
2024-01-13 21:31:02 +01:00
@@ -198,6 +198,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
// Paper end - initialize global and world-defaults configuration
+ org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2024-01-24 13:07:40 +01:00
index 43406c5d7fdd3cd7c88aad5a86252eab28a88c0b..0e18637f9ac0cf69f370d46081664456b4b30c4c 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
Updated Upstream (Bukkit/CraftBukkit) (#10034)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
f29cb801 Separate checkstyle-suppressions file is not required
86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API
d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor
b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack
9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode()
994a6163 Attempt upgrade of resolver libraries
CraftBukkit Changes:
b3b43a6ad Add Checkstyle check for unused imports
13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names
3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API
2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor
1dbdbbed4 PR-1238: Remove unnecessary sign ticking
659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper
e37e29ce0 Increase outdated build delay
c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack
492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode()
e11fbb9d7 Upgrade MySQL driver
9f3a0bd2a Attempt upgrade of resolver libraries
60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion
Spigot Changes:
06d602e7 Rebuild patches
2023-12-17 03:09:28 +01:00
@@ -915,6 +915,7 @@ public final class CraftServer implements Server {
2021-06-11 14:02:28 +02:00
@Override
public void reload() {
+ org.spigotmc.WatchdogThread.hasStarted = false; // Paper - Disable watchdog early timeout on reload
2021-06-13 01:45:00 +02:00
this.reloadCount++;
this.configuration = YamlConfiguration.loadConfiguration(this.getConfigFile());
this.commandsConfiguration = YamlConfiguration.loadConfiguration(this.getCommandsConfigFile());
Updated Upstream (Bukkit/CraftBukkit) (#10034)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
f29cb801 Separate checkstyle-suppressions file is not required
86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API
d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor
b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack
9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode()
994a6163 Attempt upgrade of resolver libraries
CraftBukkit Changes:
b3b43a6ad Add Checkstyle check for unused imports
13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names
3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API
2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor
1dbdbbed4 PR-1238: Remove unnecessary sign ticking
659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper
e37e29ce0 Increase outdated build delay
c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack
492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode()
e11fbb9d7 Upgrade MySQL driver
9f3a0bd2a Attempt upgrade of resolver libraries
60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion
Spigot Changes:
06d602e7 Rebuild patches
2023-12-17 03:09:28 +01:00
@@ -1004,6 +1005,7 @@ public final class CraftServer implements Server {
2021-06-13 01:45:00 +02:00
this.enablePlugins(PluginLoadOrder.STARTUP);
this.enablePlugins(PluginLoadOrder.POSTWORLD);
this.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.RELOAD));
2021-06-11 14:02:28 +02:00
+ org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload
}
@Override
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
2024-01-21 17:39:05 +01:00
index 9c5c19ab9dc14d844631f47a93f3349409efdf43..56dbc23f10d946a7ec992b08fd868f3ee5089068 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -229,7 +229,7 @@ public class SpigotConfig
2021-06-13 01:45:00 +02:00
SpigotConfig.restartScript = SpigotConfig.getString( "settings.restart-script", SpigotConfig.restartScript );
SpigotConfig.restartMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.restart", "Server is restarting" ) );
SpigotConfig.commands.put( "restart", new RestartCommand( "restart" ) );
2023-10-27 01:34:58 +02:00
- WatchdogThread.doStart( SpigotConfig.timeoutTime, SpigotConfig.restartOnCrash );
+ // WatchdogThread.doStart( SpigotConfig.timeoutTime, SpigotConfig.restartOnCrash ); // Paper - moved to after paper config initialization
2021-06-11 14:02:28 +02:00
}
public static boolean bungee;
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
2024-01-24 14:05:59 +01:00
index ce17005f8c255eb3096736ef9f0d1de64b612d79..017c2eadbc5dfec155c21b5d8a80f0b1e380398e 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
2024-01-24 13:07:40 +01:00
@@ -14,6 +14,10 @@ public class WatchdogThread extends Thread
2021-06-11 14:02:28 +02:00
private static WatchdogThread instance;
private long timeoutTime;
private boolean restart;
+ private final long earlyWarningEvery; // Paper - Timeout time for just printing a dump but not restarting
+ private final long earlyWarningDelay; // Paper
+ public static volatile boolean hasStarted; // Paper
+ private long lastEarlyWarning; // Paper - Keep track of short dump times to avoid spamming console with short dumps
private volatile long lastTick;
private volatile boolean stopping;
2024-01-24 13:07:40 +01:00
@@ -22,6 +26,8 @@ public class WatchdogThread extends Thread
2021-06-11 14:02:28 +02:00
super( "Paper Watchdog Thread" );
this.timeoutTime = timeoutTime;
this.restart = restart;
2022-06-09 10:51:45 +02:00
+ earlyWarningEvery = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper
+ earlyWarningDelay = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningDelay, timeoutTime); // Paper
2021-06-11 14:02:28 +02:00
}
private static long monotonicMillis()
2024-01-24 13:07:40 +01:00
@@ -61,9 +67,18 @@ public class WatchdogThread extends Thread
2021-06-13 01:45:00 +02:00
while ( !this.stopping )
2021-06-11 14:02:28 +02:00
{
2021-06-13 01:45:00 +02:00
//
- if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
2021-06-11 14:02:28 +02:00
+ // Paper start
+ Logger log = Bukkit.getServer().getLogger();
2021-06-13 01:45:00 +02:00
+ long currentTime = WatchdogThread.monotonicMillis();
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
2021-06-11 14:02:28 +02:00
{
- Logger log = Bukkit.getServer().getLogger();
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime;
+ // Don't spam early warning dumps
+ if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue;
+ if ( !isLongTimeout && MinecraftServer.getServer().hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
+ lastEarlyWarning = currentTime;
+ if (isLongTimeout) {
+ // Paper end
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
2024-01-24 14:05:59 +01:00
@@ -92,29 +107,45 @@ public class WatchdogThread extends Thread
}
2021-06-11 14:02:28 +02:00
}
2024-01-24 14:05:59 +01:00
// Paper end
2021-06-11 14:02:28 +02:00
+ } else
+ {
+ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---");
+ log.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump");
+ }
+ // Paper end - Different message for short timeout
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
2021-06-13 01:45:00 +02:00
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
2021-06-11 14:02:28 +02:00
log.log( Level.SEVERE, "------------------------------" );
//
+ // Paper start - Only print full dump on long timeouts
+ if ( isLongTimeout )
+ {
log.log( Level.SEVERE, "Entire Thread Dump:" );
ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads( true, true );
for ( ThreadInfo thread : threads )
{
2021-06-13 01:45:00 +02:00
WatchdogThread.dumpThread( thread, log );
2021-06-11 14:02:28 +02:00
}
+ } else {
+ log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---");
+ }
+
log.log( Level.SEVERE, "------------------------------" );
+ if ( isLongTimeout )
+ {
2021-06-13 01:45:00 +02:00
if ( this.restart && !MinecraftServer.getServer().hasStopped() )
2021-06-11 14:02:28 +02:00
{
RestartCommand.restart();
}
break;
+ } // Paper end
}
try
{
- sleep( 10000 );
+ sleep( 1000 ); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout
} catch ( InterruptedException ex )
{
2023-10-27 01:34:58 +02:00
this.interrupt();