From daa17c3e8b8487227b64226a96f05acde70cbedd Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 24 Nov 2024 22:12:43 +0100 Subject: [PATCH 1/2] Wrap CheckpointUtils for OpenJDK support, remove Border debug messages --- .../steamwar/fightsystem/listener/Border.java | 2 - .../src/de/steamwar/core/CheckpointUtils.java | 181 ++++++++++-------- 2 files changed, 100 insertions(+), 83 deletions(-) diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Border.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Border.java index 6ab6605e..602a8e11 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Border.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Border.java @@ -64,7 +64,6 @@ public class Border { ghostBarriers.put(player.getUniqueId(), new HashSet<>()); lastLocation.put(player.getUniqueId(), player.getLocation()); - FightSystem.getPlugin().getLogger().log(Level.INFO, () -> player.getName() + " was added to border " + name); } public boolean contains(Player player) { @@ -72,7 +71,6 @@ public class Border { } public void removePlayer(Player player) { - FightSystem.getPlugin().getLogger().log(Level.INFO, () -> player.getName() + " was removed from border " + name); lastLocation.remove(player.getUniqueId()); Set blocks = ghostBarriers.remove(player.getUniqueId()); if(blocks == null || !player.isOnline()) diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java index d65d7311..f274acfc 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java @@ -45,103 +45,122 @@ public class CheckpointUtils { private CheckpointUtils() {} public static void signalHandler() { - Signal.handle(new Signal("USR1"), signal -> Bukkit.getScheduler().runTask(Core.getInstance(), CheckpointUtils::freeze)); + try { + J9Wrapper.signalHandler(); + } catch (NoClassDefFoundError e) { + //ignore + } } public static void freeze() { - String checkpointFile = System.getProperty("checkpoint"); - if(!CRIUSupport.isCheckpointAllowed() || checkpointFile == null) { - Bukkit.shutdown(); - return; - } - - Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null)); - - List networkManagers = TinyProtocol.networkManagers.get(TinyProtocol.getServerConnection(Core.getInstance())); - if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) { - Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing"); - Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); - return; - } - - Path path = FileSystems.getDefault().getPath(checkpointFile); - try { - freezeInternal(path); - } catch (Exception e) { - String message = e.getMessage() != null ? e.getMessage() : ""; - if(message.contains("Connected TCP socket")) { - Core.getInstance().getLogger().log(Level.INFO, "Connected TCP socket, waiting for checkpointing"); + J9Wrapper.freeze(); + } catch (NoClassDefFoundError e) { + //ignore + } + } + + private static class J9Wrapper { + private static void signalHandler() { + Signal.handle(new Signal("USR1"), signal -> Bukkit.getScheduler().runTask(Core.getInstance(), CheckpointUtils::freeze)); + } + + private static void freeze() { + String checkpointFile = System.getProperty("checkpoint"); + if(!CRIUSupport.isCheckpointAllowed() || checkpointFile == null) { + Bukkit.shutdown(); + return; + } + + Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null)); + + List networkManagers = TinyProtocol.networkManagers.get(TinyProtocol.getServerConnection(Core.getInstance())); + if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) { + Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing"); Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); return; } - Bukkit.shutdown(); + Path path = FileSystems.getDefault().getPath(checkpointFile); - if(!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated - throw new SecurityException(e); - } finally { - // Delete checkpoint - try (Stream stream = Files.walk(path)) { - stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); - } catch (IOException e) { - //ignore + try { + freezeInternal(path); + } catch (Exception e) { + String message = e.getMessage() != null ? e.getMessage() : ""; + if(message.contains("Connected TCP socket")) { + Core.getInstance().getLogger().log(Level.INFO, "Connected TCP socket, waiting for checkpointing"); + Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); + return; + } + + Bukkit.shutdown(); + + if(!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated + throw new SecurityException(e); + } finally { + // Delete checkpoint + try (Stream stream = Files.walk(path)) { + stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } catch (IOException e) { + //ignore + } } } - } - private static final Reflection.FieldAccessor channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class); - private static final Reflection.MethodInvoker bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class); - private static void freezeInternal(Path path) throws Exception { - Bukkit.getPluginManager().callEvent(new CRIUSleepEvent()); - Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave); - Statement.closeAll(); - // Close socket - Via.getManager().getInjector().uninject(); - Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance()); - List channels = channelFutures.get(serverConnection); - for(Object future : channels) { - ((ChannelFuture) future).channel().close().syncUninterruptibly(); - } - channels.clear(); + private static final Reflection.FieldAccessor channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class); + private static final Reflection.MethodInvoker bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class); + private static void freezeInternal(Path path) throws Exception { + Bukkit.getPluginManager().callEvent(new CRIUSleepEvent()); + Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave); + Statement.closeAll(); - System.runFinalization(); - System.gc(); - - // Do the checkpoint - path.toFile().mkdirs(); - CRIUSupport criu = new CRIUSupport(path); - criu.setAutoDedup(true); - criu.setFileLocks(true); - criu.setShellJob(true); - criu.setLogFile("criu.log"); - try { - criu.checkpointJVM(); - } catch (JVMCRIUException e) { - Path logfile = path.resolve("criu.log"); - if(logfile.toFile().exists()) - throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e); - - throw e; - } - - // Get new port - int port; - try (DataInputStream stream = new DataInputStream(Files.newInputStream(path.resolve("port").toFile().toPath()))) { - port = stream.readInt(); - } - - // Reopen socket - bind.invoke(serverConnection, InetAddress.getLoopbackAddress(), port); - if(Core.getVersion() > 12) { + // Close socket + Via.getManager().getInjector().uninject(); + Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance()); + List channels = channelFutures.get(serverConnection); for(Object future : channels) { - ((ChannelFuture) future).channel().config().setAutoRead(true); + ((ChannelFuture) future).channel().close().syncUninterruptibly(); } - } - Via.getManager().getInjector().inject(); + channels.clear(); - Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent()); - Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored"); + System.runFinalization(); + System.gc(); + + // Do the checkpoint + path.toFile().mkdirs(); + CRIUSupport criu = new CRIUSupport(path); + criu.setAutoDedup(true); + criu.setFileLocks(true); + criu.setShellJob(true); + criu.setLogFile("criu.log"); + try { + criu.checkpointJVM(); + } catch (JVMCRIUException e) { + Path logfile = path.resolve("criu.log"); + if(logfile.toFile().exists()) + throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e); + + throw e; + } + + // Get new port + int port; + try (DataInputStream stream = new DataInputStream(Files.newInputStream(path.resolve("port").toFile().toPath()))) { + port = stream.readInt(); + } + + // Reopen socket + bind.invoke(serverConnection, InetAddress.getLoopbackAddress(), port); + if(Core.getVersion() > 12) { + for(Object future : channels) { + ((ChannelFuture) future).channel().config().setAutoRead(true); + } + } + Via.getManager().getInjector().inject(); + + Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent()); + Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored"); + } } } From afadf0b9dd4eaf592f96a129418b4207984cbf29 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 24 Nov 2024 22:17:11 +0100 Subject: [PATCH 2/2] Wrap CheckpointUtils for OpenJDK support --- .../src/de/steamwar/core/CheckpointUtils.java | 130 +-------------- .../de/steamwar/core/CheckpointUtilsJ9.java | 148 ++++++++++++++++++ 2 files changed, 150 insertions(+), 128 deletions(-) create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java index f274acfc..56e71994 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java @@ -19,34 +19,12 @@ package de.steamwar.core; -import com.comphenix.tinyprotocol.Reflection; -import com.comphenix.tinyprotocol.TinyProtocol; -import com.viaversion.viaversion.api.Via; -import de.steamwar.sql.internal.Statement; -import io.netty.channel.ChannelFuture; -import org.bukkit.Bukkit; -import org.eclipse.openj9.criu.CRIUSupport; -import org.eclipse.openj9.criu.JVMCRIUException; -import sun.misc.Signal; - -import java.io.DataInputStream; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Comparator; -import java.util.List; -import java.util.logging.Level; -import java.util.stream.Stream; - public class CheckpointUtils { private CheckpointUtils() {} public static void signalHandler() { try { - J9Wrapper.signalHandler(); + CheckpointUtilsJ9.signalHandler(); } catch (NoClassDefFoundError e) { //ignore } @@ -54,113 +32,9 @@ public class CheckpointUtils { public static void freeze() { try { - J9Wrapper.freeze(); + CheckpointUtilsJ9.freeze(); } catch (NoClassDefFoundError e) { //ignore } } - - private static class J9Wrapper { - private static void signalHandler() { - Signal.handle(new Signal("USR1"), signal -> Bukkit.getScheduler().runTask(Core.getInstance(), CheckpointUtils::freeze)); - } - - private static void freeze() { - String checkpointFile = System.getProperty("checkpoint"); - if(!CRIUSupport.isCheckpointAllowed() || checkpointFile == null) { - Bukkit.shutdown(); - return; - } - - Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null)); - - List networkManagers = TinyProtocol.networkManagers.get(TinyProtocol.getServerConnection(Core.getInstance())); - if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) { - Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing"); - Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); - return; - } - - Path path = FileSystems.getDefault().getPath(checkpointFile); - - try { - freezeInternal(path); - } catch (Exception e) { - String message = e.getMessage() != null ? e.getMessage() : ""; - if(message.contains("Connected TCP socket")) { - Core.getInstance().getLogger().log(Level.INFO, "Connected TCP socket, waiting for checkpointing"); - Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); - return; - } - - Bukkit.shutdown(); - - if(!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated - throw new SecurityException(e); - } finally { - // Delete checkpoint - try (Stream stream = Files.walk(path)) { - stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); - } catch (IOException e) { - //ignore - } - } - } - - - private static final Reflection.FieldAccessor channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class); - private static final Reflection.MethodInvoker bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class); - private static void freezeInternal(Path path) throws Exception { - Bukkit.getPluginManager().callEvent(new CRIUSleepEvent()); - Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave); - Statement.closeAll(); - - // Close socket - Via.getManager().getInjector().uninject(); - Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance()); - List channels = channelFutures.get(serverConnection); - for(Object future : channels) { - ((ChannelFuture) future).channel().close().syncUninterruptibly(); - } - channels.clear(); - - System.runFinalization(); - System.gc(); - - // Do the checkpoint - path.toFile().mkdirs(); - CRIUSupport criu = new CRIUSupport(path); - criu.setAutoDedup(true); - criu.setFileLocks(true); - criu.setShellJob(true); - criu.setLogFile("criu.log"); - try { - criu.checkpointJVM(); - } catch (JVMCRIUException e) { - Path logfile = path.resolve("criu.log"); - if(logfile.toFile().exists()) - throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e); - - throw e; - } - - // Get new port - int port; - try (DataInputStream stream = new DataInputStream(Files.newInputStream(path.resolve("port").toFile().toPath()))) { - port = stream.readInt(); - } - - // Reopen socket - bind.invoke(serverConnection, InetAddress.getLoopbackAddress(), port); - if(Core.getVersion() > 12) { - for(Object future : channels) { - ((ChannelFuture) future).channel().config().setAutoRead(true); - } - } - Via.getManager().getInjector().inject(); - - Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent()); - Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored"); - } - } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java new file mode 100644 index 00000000..cde82084 --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java @@ -0,0 +1,148 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2024 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core; + +import com.comphenix.tinyprotocol.Reflection; +import com.comphenix.tinyprotocol.TinyProtocol; +import com.viaversion.viaversion.api.Via; +import de.steamwar.sql.internal.Statement; +import io.netty.channel.ChannelFuture; +import org.bukkit.Bukkit; +import org.eclipse.openj9.criu.CRIUSupport; +import org.eclipse.openj9.criu.JVMCRIUException; +import sun.misc.Signal; + +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Stream; + +class CheckpointUtilsJ9 { + private CheckpointUtilsJ9() {} + + static void signalHandler() { + Signal.handle(new Signal("USR1"), signal -> Bukkit.getScheduler().runTask(Core.getInstance(), CheckpointUtils::freeze)); + } + + static void freeze() { + String checkpointFile = System.getProperty("checkpoint"); + if(!CRIUSupport.isCheckpointAllowed() || checkpointFile == null) { + Bukkit.shutdown(); + return; + } + + Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null)); + + List networkManagers = TinyProtocol.networkManagers.get(TinyProtocol.getServerConnection(Core.getInstance())); + if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) { + Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing"); + Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); + return; + } + + Path path = FileSystems.getDefault().getPath(checkpointFile); + + try { + freezeInternal(path); + } catch (Exception e) { + String message = e.getMessage() != null ? e.getMessage() : ""; + if(message.contains("Connected TCP socket")) { + Core.getInstance().getLogger().log(Level.INFO, "Connected TCP socket, waiting for checkpointing"); + Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1); + return; + } + + Bukkit.shutdown(); + + if(!message.contains("Can't dump ghost file") && !message.contains("Can't create link remap")) // File/Jar has been updated + throw new SecurityException(e); + } finally { + // Delete checkpoint + try (Stream stream = Files.walk(path)) { + stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } catch (IOException e) { + //ignore + } + } + } + + + private static final Reflection.FieldAccessor channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class); + private static final Reflection.MethodInvoker bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class); + private static void freezeInternal(Path path) throws Exception { + Bukkit.getPluginManager().callEvent(new CRIUSleepEvent()); + Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave); + Statement.closeAll(); + + // Close socket + Via.getManager().getInjector().uninject(); + Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance()); + List channels = channelFutures.get(serverConnection); + for(Object future : channels) { + ((ChannelFuture) future).channel().close().syncUninterruptibly(); + } + channels.clear(); + + System.runFinalization(); + System.gc(); + + // Do the checkpoint + path.toFile().mkdirs(); + CRIUSupport criu = new CRIUSupport(path); + criu.setAutoDedup(true); + criu.setFileLocks(true); + criu.setShellJob(true); + criu.setLogFile("criu.log"); + try { + criu.checkpointJVM(); + } catch (JVMCRIUException e) { + Path logfile = path.resolve("criu.log"); + if(logfile.toFile().exists()) + throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e); + + throw e; + } + + // Get new port + int port; + try (DataInputStream stream = new DataInputStream(Files.newInputStream(path.resolve("port").toFile().toPath()))) { + port = stream.readInt(); + } + + // Reopen socket + bind.invoke(serverConnection, InetAddress.getLoopbackAddress(), port); + if(Core.getVersion() > 12) { + for(Object future : channels) { + ((ChannelFuture) future).channel().config().setAutoRead(true); + } + } + Via.getManager().getInjector().inject(); + + Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent()); + Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored"); + } +}