|
|
|
|
@@ -6,7 +6,6 @@ import java.util.logging.Level;
|
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
|
import org.bukkit.craftbukkit.CraftServer;
|
|
|
|
|
import org.spigotmc.RestartCommand;
|
|
|
|
|
import org.spigotmc.WatchdogThread;
|
|
|
|
|
import org.spongepowered.asm.mixin.Final;
|
|
|
|
|
@@ -23,6 +22,8 @@ import net.minecraft.server.MinecraftServer;
|
|
|
|
|
public abstract class Watchcat extends Thread {
|
|
|
|
|
@Shadow private static WatchdogThread instance;
|
|
|
|
|
@Shadow private @Final long timeoutTime;
|
|
|
|
|
@Shadow private @Final long shortTimeout; // Paper - Timeout time for just printing a dump but not restarting
|
|
|
|
|
@Shadow private long lastShortDump; // Paper - Keep track of short dump times to avoid spamming console with short dumps
|
|
|
|
|
@Shadow private @Final boolean restart;
|
|
|
|
|
@Shadow private volatile long lastTick;
|
|
|
|
|
@Shadow private volatile boolean stopping;
|
|
|
|
|
@@ -39,47 +40,67 @@ public abstract class Watchcat extends Thread {
|
|
|
|
|
public void run() {
|
|
|
|
|
while (!stopping) {
|
|
|
|
|
//
|
|
|
|
|
if (lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) { // Paper - Add property to disable
|
|
|
|
|
Logger log = Bukkit.getServer().getLogger();
|
|
|
|
|
log.log(Level.SEVERE, "Server has stopped responding!");
|
|
|
|
|
log.log(Level.SEVERE, "Please report this to https://github.com/Akarin-project/Akarin/issues");
|
|
|
|
|
log.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
|
|
|
|
log.log(Level.SEVERE, "Akarin version: " + Bukkit.getServer().getVersion());
|
|
|
|
|
//
|
|
|
|
|
if (net.minecraft.server.World.haveWeSilencedAPhysicsCrash) {
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
log.log(Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed");
|
|
|
|
|
log.log(Level.SEVERE, "near " + net.minecraft.server.World.blockLocation);
|
|
|
|
|
}
|
|
|
|
|
// Paper start - Warn in watchdog if an excessive velocity was ever set
|
|
|
|
|
if (CraftServer.excessiveVelEx != null) {
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
log.log(Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity");
|
|
|
|
|
log.log(Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated");
|
|
|
|
|
log.log(Level.SEVERE, CraftServer.excessiveVelEx.getMessage());
|
|
|
|
|
for (StackTraceElement stack : CraftServer.excessiveVelEx.getStackTrace()) {
|
|
|
|
|
log.log(Level.SEVERE, "\t\t" + stack);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
long currentTime = System.currentTimeMillis(); // Paper - do we REALLY need to call this method multiple times?
|
|
|
|
|
if (lastTick != 0 && currentTime > lastTick + shortTimeout && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable and short timeout
|
|
|
|
|
{
|
|
|
|
|
// Paper start
|
|
|
|
|
boolean isLongTimeout = currentTime > lastTick + timeoutTime;
|
|
|
|
|
// Don't spam short dumps
|
|
|
|
|
if (!isLongTimeout && currentTime < lastShortDump + shortTimeout)
|
|
|
|
|
continue;
|
|
|
|
|
lastShortDump = currentTime;
|
|
|
|
|
// Paper end
|
|
|
|
|
Logger log = Bukkit.getServer().getLogger();
|
|
|
|
|
// Paper start - Different message when it's a short timeout
|
|
|
|
|
if (isLongTimeout) {
|
|
|
|
|
log.log(Level.SEVERE, "The server has stopped responding!");
|
|
|
|
|
log.log(Level.SEVERE, "Please report this to https://github.com/Akarin-project/Akarin/issues");
|
|
|
|
|
log.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
|
|
|
|
log.log(Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion());
|
|
|
|
|
//
|
|
|
|
|
if (net.minecraft.server.World.haveWeSilencedAPhysicsCrash) {
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
log.log(Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed");
|
|
|
|
|
log.log(Level.SEVERE, "near " + net.minecraft.server.World.blockLocation);
|
|
|
|
|
}
|
|
|
|
|
// Paper start - Warn in watchdog if an excessive velocity was ever set
|
|
|
|
|
if (org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null) {
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
log.log(Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity");
|
|
|
|
|
log.log(Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated");
|
|
|
|
|
log.log(Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
|
|
|
|
for (StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace()) {
|
|
|
|
|
log.log(Level.SEVERE, "\t\t" + stack);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Paper end
|
|
|
|
|
} else {
|
|
|
|
|
log.log(Level.SEVERE, "The server has not responded for " + shortTimeout / 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 Akarin!):");
|
|
|
|
|
dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE), log);
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
//
|
|
|
|
|
log.log(Level.SEVERE, "Entire Thread Dump:");
|
|
|
|
|
ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
|
|
|
|
|
for (ThreadInfo thread : threads) {
|
|
|
|
|
dumpThread(thread, log);
|
|
|
|
|
}
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
|
|
|
|
|
if (restart) RestartCommand.restart(); // GC Inlined
|
|
|
|
|
break;
|
|
|
|
|
// 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) {
|
|
|
|
|
dumpThread(thread, log);
|
|
|
|
|
}
|
|
|
|
|
log.log(Level.SEVERE, "------------------------------");
|
|
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
|
RestartCommand.restart();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} // Paper end
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
sleep(9000); // Akarin
|
|
|
|
|
sleep(1000); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout
|
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
|
interrupt();
|
|
|
|
|
}
|
|
|
|
|
|