ServerWatchdog.java

net.minecraft.server.dedicated.ServerWatchdog

信息

  • 全限定名:net.minecraft.server.dedicated.ServerWatchdog
  • 类型:public class
  • 包:net.minecraft.server.dedicated
  • 源码路径:src/main/java/net/minecraft/server/dedicated/ServerWatchdog.java
  • 起始行号:L23
  • 实现:Runnable
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L24
    • 说明:

      TODO

  • MAX_SHUTDOWN_TIME

    • 类型: long
    • 修饰符: private static final
    • 源码定位: L25
    • 说明:

      TODO

  • SHUTDOWN_STATUS

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L26
    • 说明:

      TODO

  • server

    • 类型: DedicatedServer
    • 修饰符: private final
    • 源码定位: L27
    • 说明:

      TODO

  • maxTickTimeNanos

    • 类型: long
    • 修饰符: private final
    • 源码定位: L28
    • 说明:

      TODO

内部类/嵌套类型

构造器

public ServerWatchdog(DedicatedServer server) @ L30

  • 构造器名:ServerWatchdog
  • 源码定位:L30
  • 修饰符:public

参数:

  • server: DedicatedServer

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void run() @ L35

  • 方法名:run
  • 源码定位:L35
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public static CrashReport createWatchdogCrashReport(String message, long mainThreadId) @ L77

  • 方法名:createWatchdogCrashReport
  • 源码定位:L77
  • 返回类型:CrashReport
  • 修饰符:public static

参数:

  • message: String
  • mainThreadId: long

说明:

TODO

private void exit() @ L98

  • 方法名:exit
  • 源码定位:L98
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

代码

public class ServerWatchdog implements Runnable {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final long MAX_SHUTDOWN_TIME = 10000L;
    private static final int SHUTDOWN_STATUS = 1;
    private final DedicatedServer server;
    private final long maxTickTimeNanos;
 
    public ServerWatchdog(DedicatedServer server) {
        this.server = server;
        this.maxTickTimeNanos = server.getMaxTickLength() * TimeUtil.NANOSECONDS_PER_MILLISECOND;
    }
 
    @Override
    public void run() {
        while (this.server.isRunning()) {
            long nextTickTimeNanos = this.server.getNextTickTime();
            long currentTimeNanos = Util.getNanos();
            long deltaNanos = currentTimeNanos - nextTickTimeNanos;
            if (deltaNanos > this.maxTickTimeNanos) {
                LOGGER.error(
                    LogUtils.FATAL_MARKER,
                    "A single server tick took {} seconds (should be max {})",
                    String.format(Locale.ROOT, "%.2f", (float)deltaNanos / (float)TimeUtil.NANOSECONDS_PER_SECOND),
                    String.format(Locale.ROOT, "%.2f", this.server.tickRateManager().millisecondsPerTick() / (float)TimeUtil.MILLISECONDS_PER_SECOND)
                );
                LOGGER.error(LogUtils.FATAL_MARKER, "Considering it to be crashed, server will forcibly shutdown.");
                CrashReport report = createWatchdogCrashReport("Watching Server", this.server.getRunningThread().threadId());
                this.server.fillSystemReport(report.getSystemReport());
                CrashReportCategory serverStats = report.addCategory("Performance stats");
                serverStats.setDetail("Random tick rate", () -> this.server.getGameRules().getAsString(GameRules.RANDOM_TICK_SPEED));
                serverStats.setDetail(
                    "Level stats",
                    () -> Streams.stream(this.server.getAllLevels())
                        .map(level -> level.dimension().identifier() + ": " + level.getWatchdogStats())
                        .collect(Collectors.joining(",\n"))
                );
                Bootstrap.realStdoutPrintln("Crash report:\n" + report.getFriendlyReport(ReportType.CRASH));
                Path file = this.server.getServerDirectory().resolve("crash-reports").resolve("crash-" + Util.getFilenameFormattedDateTime() + "-server.txt");
                if (report.saveToFile(file, ReportType.CRASH)) {
                    LOGGER.error("This crash report has been saved to: {}", file.toAbsolutePath());
                } else {
                    LOGGER.error("We were unable to save this crash report to disk.");
                }
 
                this.exit();
            }
 
            try {
                Thread.sleep((nextTickTimeNanos + this.maxTickTimeNanos - currentTimeNanos) / TimeUtil.NANOSECONDS_PER_MILLISECOND);
            } catch (InterruptedException var10) {
            }
        }
    }
 
    public static CrashReport createWatchdogCrashReport(String message, long mainThreadId) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
        StringBuilder builder = new StringBuilder();
        Error exception = new Error("Watchdog");
 
        for (ThreadInfo threadInfo : threadInfos) {
            if (threadInfo.getThreadId() == mainThreadId) {
                exception.setStackTrace(threadInfo.getStackTrace());
            }
 
            builder.append(threadInfo);
            builder.append("\n");
        }
 
        CrashReport report = new CrashReport(message, exception);
        CrashReportCategory threadDump = report.addCategory("Thread Dump");
        threadDump.setDetail("Threads", builder);
        return report;
    }
 
    private void exit() {
        try {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                {
                    Objects.requireNonNull(ServerWatchdog.this);
                }
 
                @Override
                public void run() {
                    Runtime.getRuntime().halt(1);
                }
            }, 10000L);
            System.exit(1);
        } catch (Throwable var2) {
            Runtime.getRuntime().halt(1);
        }
    }
}

引用的其他类

  • GLFWErrorCapture

    • 引用位置: 构造调用
    • 关联成员: Error()
  • CrashReport

    • 引用位置: 构造调用/返回值
    • 关联成员: CrashReport()
  • DeltaTracker

    • 引用位置: 构造调用
    • 关联成员: Timer()
  • LoggedChatMessage

    • 引用位置: 方法调用
    • 关联成员: System.exit()
  • Bootstrap

    • 引用位置: 方法调用
    • 关联成员: Bootstrap.realStdoutPrintln()
  • DedicatedServer

    • 引用位置: 参数/字段
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getFilenameFormattedDateTime(), Util.getNanos()