From c0b111eabc0ffaf94b8e314dade431b6e737cbfd Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 16 Jan 2024 12:36:49 +0100 Subject: [PATCH] First tested checkpoint implementation --- .../src/de/steamwar/core/CheckpointUtils.java | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java b/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java index cac5a2d..8cedf02 100644 --- a/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java +++ b/SpigotCore_Main/src/de/steamwar/core/CheckpointUtils.java @@ -21,6 +21,7 @@ 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; @@ -28,22 +29,46 @@ import org.eclipse.openj9.criu.CRIUSupport; import org.eclipse.openj9.criu.JVMCRIUException; 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() {} + 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); public static void freeze() { - Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null)); + Path path = FileSystems.getDefault().getPath(System.getProperty("checkpoint")); + + try { + freezeInternal(path); + } catch (Exception e) { + Bukkit.shutdown(); + 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 void freezeInternal(Path path) throws Exception { Statement.closeAll(); // Close socket + Via.getManager().getInjector().uninject(); Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance()); List channels = channelFutures.get(serverConnection); for(Object future : channels) { @@ -51,13 +76,13 @@ public class CheckpointUtils { } channels.clear(); - // Do the snapshot - Path path = FileSystems.getDefault().getPath("/tmp/checkpoints/" + Core.getVersion() + "/" + Bukkit.getWorlds().get(0).getName()); + // Do the checkpoint path.toFile().mkdirs(); CRIUSupport criu = new CRIUSupport(path); criu.setAutoDedup(true); - //criu.setShellJob(true); - //criu.setWorkDir(path); criu.setLogFile("criu.log"); + criu.setFileLocks(true); + criu.setShellJob(true); + criu.setLogFile("criu.log"); try { criu.checkpointJVM(); } catch (JVMCRIUException e) { @@ -69,9 +94,6 @@ public class CheckpointUtils { int port; try (DataInputStream stream = new DataInputStream(Files.newInputStream(path.resolve("port").toFile().toPath()))) { port = stream.readInt(); - } catch (IOException e) { - Bukkit.shutdown(); - throw new SecurityException(e); } // Reopen socket @@ -81,5 +103,8 @@ public class CheckpointUtils { ((ChannelFuture) future).channel().config().setAutoRead(true); } } + Via.getManager().getInjector().inject(); + + Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored"); } }