e9950b70d3
This greatly extends the timings improvements I've done in recent commits, and brings timings to fully cover the entire tick. The timings system also now tracks when specific timings causes the server to lose TPS. The timings are also able to be turned on "on demand", meaning you do not need to restart the server to enable them. This commit also overhauls the Entity Activation Range feature, fixing bugs, adding more immunities, and improving the performance of it. It also fixes a regression with a recent Spigot commit that broke the entire Entity Activation Range feature. This commit had to move the Tick Loop patch before timings because there was a change done there to time the entire tick, so lots of renames. These 2 commits had to be bundled together to simplify applying them and reduce redundant conflict resolution.
300 lines
12 KiB
Diff
300 lines
12 KiB
Diff
From 5a0d969c584b848bd8fcb62f4b3178c071801edb Mon Sep 17 00:00:00 2001
|
|
From: md_5 <md_5@live.com.au>
|
|
Date: Sat, 23 Feb 2013 12:33:20 +1100
|
|
Subject: [PATCH] Watchdog Thread.
|
|
|
|
---
|
|
.../java/net/minecraft/server/MinecraftServer.java | 2 +
|
|
src/main/java/org/bukkit/craftbukkit/Spigot.java | 76 +++++++++++++++++-
|
|
src/main/java/org/spigotmc/RestartCommand.java | 23 ++++++
|
|
src/main/java/org/spigotmc/WatchdogThread.java | 93 ++++++++++++++++++++++
|
|
src/main/resources/configurations/bukkit.yml | 3 +
|
|
5 files changed, 195 insertions(+), 2 deletions(-)
|
|
create mode 100644 src/main/java/org/spigotmc/RestartCommand.java
|
|
create mode 100644 src/main/java/org/spigotmc/WatchdogThread.java
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index aa6a14a..6005fac 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -421,6 +421,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo
|
|
this.q();
|
|
SpigotTimings.serverTickTimer.stopTiming();
|
|
org.bukkit.CustomTimingsHandler.tick();
|
|
+ org.spigotmc.WatchdogThread.tick();
|
|
}
|
|
// Spigot end
|
|
} else {
|
|
@@ -448,6 +449,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo
|
|
this.a(crashreport);
|
|
} finally {
|
|
try {
|
|
+ org.spigotmc.WatchdogThread.doStop();
|
|
this.stop();
|
|
this.isStopped = true;
|
|
} catch (Throwable throwable1) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Spigot.java b/src/main/java/org/bukkit/craftbukkit/Spigot.java
|
|
index 3171411..6f54f7e 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/Spigot.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/Spigot.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit;
|
|
|
|
+import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import net.minecraft.server.*;
|
|
@@ -8,9 +9,11 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|
|
|
import java.util.List;
|
|
import java.util.logging.Level;
|
|
-import java.util.logging.Logger;
|
|
import org.bukkit.Bukkit;
|
|
+import org.bukkit.entity.Player;
|
|
import org.spigotmc.Metrics;
|
|
+import org.spigotmc.RestartCommand;
|
|
+import org.spigotmc.WatchdogThread;
|
|
|
|
public class Spigot {
|
|
static AxisAlignedBB maxBB = AxisAlignedBB.a(0,0,0,0,0,0);
|
|
@@ -23,6 +26,7 @@ public class Spigot {
|
|
|
|
public static void initialize(CraftServer server, SimpleCommandMap commandMap, YamlConfiguration configuration) {
|
|
commandMap.register("bukkit", new org.bukkit.craftbukkit.command.TicksPerSecondCommand("tps"));
|
|
+ commandMap.register("restart", new RestartCommand("restart"));
|
|
|
|
server.whitelistMessage = configuration.getString("settings.whitelist-message", server.whitelistMessage);
|
|
server.stopMessage = configuration.getString("settings.stop-message", server.stopMessage);
|
|
@@ -31,12 +35,21 @@ public class Spigot {
|
|
server.commandComplete = configuration.getBoolean("settings.command-complete", true);
|
|
server.spamGuardExclusions = configuration.getStringList("settings.spam-exclusions");
|
|
|
|
+ int configVersion = configuration.getInt("config-version");
|
|
+ switch (configVersion) {
|
|
+ case 0:
|
|
+ configuration.set("settings.timeout-time", 30);
|
|
+ }
|
|
+ configuration.set("config-version", 1);
|
|
+
|
|
+ WatchdogThread.doStart(configuration.getInt("settings.timeout-time", 30), configuration.getBoolean("settings.restart-on-crash", false));
|
|
+
|
|
server.orebfuscatorEnabled = configuration.getBoolean("orebfuscator.enable", false);
|
|
server.orebfuscatorEngineMode = configuration.getInt("orebfuscator.engine-mode", 1);
|
|
server.orebfuscatorUpdateRadius = configuration.getInt("orebfuscator.update-radius", 2);
|
|
server.orebfuscatorDisabledWorlds = configuration.getStringList("orebfuscator.disabled-worlds");
|
|
if (server.orebfuscatorEngineMode != 1 && server.orebfuscatorEngineMode != 2) {
|
|
- server.orebfuscatorEngineMode = 1;
|
|
+ server.orebfuscatorEngineMode = 1;
|
|
}
|
|
|
|
if (server.chunkGCPeriod == 0) {
|
|
@@ -265,4 +278,63 @@ public class Spigot {
|
|
SpigotTimings.checkIfActiveTimer.stopTiming();
|
|
return isActive;
|
|
}
|
|
+
|
|
+ public static void restart() {
|
|
+ try {
|
|
+ String startupScript = MinecraftServer.getServer().server.configuration.getString("settings.restart-script-location", "");
|
|
+ final File file = new File(startupScript);
|
|
+ if (file.isFile()) {
|
|
+ System.out.println("Attempting to restart with " + startupScript);
|
|
+
|
|
+ // Kick all players
|
|
+ for (Player p : Bukkit.getServer().getOnlinePlayers()) {
|
|
+ ((org.bukkit.craftbukkit.entity.CraftPlayer) p).kickPlayer("Server is restarting", true);
|
|
+ }
|
|
+ // Give the socket a chance to send the packets
|
|
+ try {
|
|
+ Thread.sleep(100);
|
|
+ } catch (InterruptedException ex) {
|
|
+ }
|
|
+ // Close the socket so we can rebind with the new process
|
|
+ MinecraftServer.getServer().ae().a();
|
|
+
|
|
+ // Give time for it to kick in
|
|
+ try {
|
|
+ Thread.sleep(100);
|
|
+ } catch (InterruptedException ex) {
|
|
+ }
|
|
+
|
|
+ // Actually shutdown
|
|
+ try {
|
|
+ MinecraftServer.getServer().stop();
|
|
+ } catch (Throwable t) {
|
|
+ }
|
|
+
|
|
+ // This will be done AFTER the server has completely halted
|
|
+ Thread shutdownHook = new Thread() {
|
|
+ @Override
|
|
+ public void run(){
|
|
+ try {
|
|
+ String os = System.getProperty("os.name").toLowerCase();
|
|
+ if (os.contains("win")) {
|
|
+ Runtime.getRuntime().exec("cmd /c start " + file.getPath());
|
|
+ } else {
|
|
+ Runtime.getRuntime().exec(new String[] { "sh", file.getPath()});
|
|
+ }
|
|
+ } catch (Exception e){
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ shutdownHook.setDaemon(true);
|
|
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
|
|
+ System.exit(0);
|
|
+ } else {
|
|
+ System.out.println("Startup script '" + startupScript + "' does not exist!");
|
|
+ }
|
|
+ } catch (Exception ex) {
|
|
+ ex.printStackTrace();
|
|
+ }
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
|
new file mode 100644
|
|
index 0000000..2d5c89f
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
|
@@ -0,0 +1,23 @@
|
|
+package org.spigotmc;
|
|
+
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.command.CommandSender;
|
|
+import org.bukkit.craftbukkit.Spigot;
|
|
+
|
|
+public class RestartCommand extends Command {
|
|
+
|
|
+ public RestartCommand(String name) {
|
|
+ super(name);
|
|
+ this.description = "Restarts the server";
|
|
+ this.usageMessage = "/restart";
|
|
+ this.setPermission("bukkit.command.restart");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean execute(CommandSender sender, String currentAlias, String[] args) {
|
|
+ if (testPermission(sender)) {
|
|
+ Spigot.restart();
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
new file mode 100644
|
|
index 0000000..10390b8
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
@@ -0,0 +1,93 @@
|
|
+package org.spigotmc;
|
|
+
|
|
+import java.lang.management.ManagementFactory;
|
|
+import java.lang.management.MonitorInfo;
|
|
+import java.lang.management.ThreadInfo;
|
|
+import java.util.logging.Level;
|
|
+import java.util.logging.Logger;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.craftbukkit.Spigot;
|
|
+
|
|
+public class WatchdogThread extends Thread {
|
|
+
|
|
+ private static WatchdogThread instance;
|
|
+ private final long timeoutTime;
|
|
+ private final boolean restart;
|
|
+ private volatile long lastTick;
|
|
+ private volatile boolean stopping;
|
|
+
|
|
+ private WatchdogThread(long timeoutTime, boolean restart) {
|
|
+ super("Spigot Watchdog Thread");
|
|
+ this.timeoutTime = timeoutTime;
|
|
+ this.restart = restart;
|
|
+ }
|
|
+
|
|
+ public static void doStart(int timeoutTime, boolean restart) {
|
|
+ if (instance == null) {
|
|
+ instance = new WatchdogThread(timeoutTime * 1000L, restart);
|
|
+ instance.start();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void tick() {
|
|
+ instance.lastTick = System.currentTimeMillis();
|
|
+ }
|
|
+
|
|
+ public static void doStop() {
|
|
+ if (instance != null) {
|
|
+ instance.stopping = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ while (!stopping) {
|
|
+ //
|
|
+ if (lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime) {
|
|
+ Logger log = Bukkit.getServer().getLogger();
|
|
+ log.log(Level.SEVERE, "The server has stopped responding!");
|
|
+ log.log(Level.SEVERE, "Please report this to http://www.spigotmc.org/");
|
|
+ log.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
|
+ log.log(Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion());
|
|
+ //
|
|
+ log.log(Level.SEVERE, "Current Thread State:");
|
|
+ ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
|
|
+ for (ThreadInfo thread : threads) {
|
|
+ if (thread.getThreadState() != State.WAITING) {
|
|
+ log.log(Level.SEVERE, "------------------------------");
|
|
+ //
|
|
+ log.log(Level.SEVERE, "Current Thread: " + thread.getThreadName());
|
|
+ log.log(Level.SEVERE, "\tPID: " + thread.getThreadId()
|
|
+ + " | Suspended: " + thread.isSuspended()
|
|
+ + " | Native: " + thread.isInNative()
|
|
+ + " | State: " + thread.getThreadState());
|
|
+ if (thread.getLockedMonitors().length != 0) {
|
|
+ log.log(Level.SEVERE, "\tThread is waiting on monitor(s):");
|
|
+ for (MonitorInfo monitor : thread.getLockedMonitors()) {
|
|
+ log.log(Level.SEVERE, "\t\tLocked on:" + monitor.getLockedStackFrame());
|
|
+ }
|
|
+ }
|
|
+ log.log(Level.SEVERE, "\tStack:");
|
|
+ //
|
|
+ StackTraceElement[] stack = thread.getStackTrace();
|
|
+ for (int line = 0; line < stack.length; line++) {
|
|
+ log.log(Level.SEVERE, "\t\t" + stack[line].toString());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ log.log(Level.SEVERE, "------------------------------");
|
|
+
|
|
+ if (restart) {
|
|
+ Spigot.restart();
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ try {
|
|
+ sleep(10000);
|
|
+ } catch (InterruptedException ex) {
|
|
+ interrupt();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml
|
|
index e568bf6..7c18391 100644
|
|
--- a/src/main/resources/configurations/bukkit.yml
|
|
+++ b/src/main/resources/configurations/bukkit.yml
|
|
@@ -31,6 +31,9 @@ settings:
|
|
command-complete: true
|
|
spam-exclusions:
|
|
- /skill
|
|
+ timeout-time: 30
|
|
+ restart-on-crash: false
|
|
+ restart-script-location: /path/to/server/start.sh
|
|
world-settings:
|
|
default:
|
|
growth-chunks-per-tick: 650
|
|
--
|
|
1.8.1.1
|
|
|