SteamWar/SpigotCore
Archiviert
13
0

Use signal handler for checkpointing #254

Zusammengeführt
Lixfel hat 3 Commits von sigusr1 nach master 2024-01-17 16:40:38 +01:00 zusammengeführt
3 geänderte Dateien mit 44 neuen und 21 gelöschten Zeilen
Nur Änderungen aus Commit 2b779ab40b werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -34,7 +34,7 @@ public class TinyProtocol implements Listener {
return getServerConnection.get(getMinecraftServer.get(getPlayerList.get(plugin.getServer())));
}
private static final Class<?> networkManager = Reflection.getClass("{nms.network}.NetworkManager");
private static final FieldAccessor<List> getConnections = Reflection.getField(serverConnection, List.class, 0, networkManager);
public static final FieldAccessor<List> networkManagers = Reflection.getField(serverConnection, List.class, 0, networkManager);
public static final TinyProtocol instance = new TinyProtocol(Core.getInstance());
private static int id = 0;
@ -54,7 +54,7 @@ public class TinyProtocol implements Listener {
private TinyProtocol(final Plugin plugin) {
this.plugin = plugin;
this.handlerName = "tiny-" + plugin.getName() + "-" + ++id;
this.connections = getConnections.get(getServerConnection(plugin));
this.connections = networkManagers.get(getServerConnection(plugin));
plugin.getServer().getPluginManager().registerEvents(this, plugin);

Datei anzeigen

@ -25,8 +25,10 @@ import com.viaversion.viaversion.api.Via;
import de.steamwar.sql.internal.Statement;
import io.netty.channel.ChannelFuture;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.eclipse.openj9.criu.CRIUSupport;
import org.eclipse.openj9.criu.JVMCRIUException;
import sun.misc.Signal;
import java.io.DataInputStream;
import java.io.File;
@ -35,6 +37,7 @@ import java.net.InetAddress;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
@ -43,28 +46,47 @@ import java.util.stream.Stream;
public class CheckpointUtils {
private CheckpointUtils() {}
private static final Reflection.FieldAccessor<List> 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() {
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<Path> stream = Files.walk(path)) {
stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
} catch (IOException e) {
//ignore
}
}
public static void signalHandler() {
Signal.handle(new Signal("USR1"), signal -> Bukkit.getScheduler().runTask(Core.getInstance(), CheckpointUtils::freeze));
Lixfel markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Ich habe das Gefühl, dass das hier einen Fehler werfen kann, alleine, weil es sun.misc.Signal ist vom package.

Ich habe das Gefühl, dass das hier einen Fehler werfen kann, alleine, weil es sun.misc.Signal ist vom package.
Veraltet
Review

Warum sollte das Fehler werfen? Ich weiß, dass es deprecated ist und ich eigentlich jdk.internal.Signal nutzen müsste, aber wir haben auch noch Java 8-Server im Betrieb, die müssen das auch können, und da gibt es noch kein jdk.internal. War sun.misc zur Entfernung in einer festgelegten JDK-Version vorgesehen?

Warum sollte das Fehler werfen? Ich weiß, dass es deprecated ist und ich eigentlich jdk.internal.Signal nutzen müsste, aber wir haben auch noch Java 8-Server im Betrieb, die müssen das auch können, und da gibt es noch kein jdk.internal. War sun.misc zur Entfernung in einer festgelegten JDK-Version vorgesehen?
Veraltet
Review

Ich glaube aktuell nichts bekannt, aber mit Sicherheit. Ich hatte eher gedacht, dass es in Java-8 nicht existiert deswegen.

Ich glaube aktuell nichts bekannt, aber mit Sicherheit. Ich hatte eher gedacht, dass es in Java-8 nicht existiert deswegen.
}
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(networkManagers.isEmpty()) {
Lixfel markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Könnten wir dieses if bitte umdrehen? Fände ich schöner!

Könnten wir dieses if bitte umdrehen? Fände ich schöner!
Path path = FileSystems.getDefault().getPath(checkpointFile);
try {
freezeInternal(path);
} catch (Exception e) {
Bukkit.shutdown();
throw new SecurityException(e);
} finally {
// Delete checkpoint
try (Stream<Path> stream = Files.walk(path)) {
stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
} catch (IOException e) {
//ignore
}
}
return;
}
Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing");
Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1);
}
private static final Reflection.FieldAccessor<List> 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.getWorlds().forEach(world -> Arrays.stream(world.getLoadedChunks()).forEach(Chunk::unload));
Lixfel markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Ist Chunk.unload auch gleich ein World save? Also das die Welt gespeichert wird?

Ist Chunk.unload auch gleich ein World save? Also das die Welt gespeichert wird?
Veraltet
Review

Ein World save ist async, deswegen nutzen wir den nicht. (Weil wir dann mitten im Speichern checkpointen, nicht unbedingt ideal).

Wenn die Chunks entladen werden, werden sie auch gespeichert, d.h. wird defakto die Welt gespeichert.

Ein World save ist async, deswegen nutzen wir den nicht. (Weil wir dann mitten im Speichern checkpointen, nicht unbedingt ideal). Wenn die Chunks entladen werden, werden sie auch gespeichert, d.h. wird defakto die Welt gespeichert.
Veraltet
Review

Ok gut zu wissen.

Ok gut zu wissen.
Statement.closeAll();
// Close socket

Datei anzeigen

@ -97,6 +97,7 @@ public class Core extends JavaPlugin{
AuthlibInjector.inject();
TinyProtocol.init();
CheckpointUtils.signalHandler();
new AntiNocom();
if(Core.getVersion() < 17 && Bukkit.getPluginManager().getPlugin("ViaVersion") != null)