577140d9ab
This will cut down on the call to areChunksLoaded drastically, which is pretty slow
302 lines
12 KiB
Diff
302 lines
12 KiB
Diff
From 51ae704ad3290541373ec51570d48c9e66743f5c 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 | 78 +++++++++++++++++-
|
|
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, 197 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 83018b0..931f6fd 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,23 @@ 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);
|
|
+ case 1:
|
|
+ configuration.set("settings.timeout-time", 60);
|
|
+ }
|
|
+ configuration.set("config-version", 2);
|
|
+
|
|
+ WatchdogThread.doStart(configuration.getInt("settings.timeout-time", 60), 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) {
|
|
@@ -264,4 +279,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
|
|
|