diff --git a/src/main/java/net/szum123321/textile_backup/Globals.java b/src/main/java/net/szum123321/textile_backup/Globals.java index 7172c2d..cf642fb 100644 --- a/src/main/java/net/szum123321/textile_backup/Globals.java +++ b/src/main/java/net/szum123321/textile_backup/Globals.java @@ -36,16 +36,13 @@ import java.util.concurrent.atomic.AtomicBoolean; public class Globals { public static final Globals INSTANCE = new Globals(); - public final static DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss"); - private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); + public final static DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss"); private ExecutorService executorService = Executors.newSingleThreadExecutor(); public final AtomicBoolean globalShutdownBackupFlag = new AtomicBoolean(true); - public boolean disableWatchdog = false; private boolean disableTMPFiles = false; - private AwaitThread restoreAwaitThread = null; private Path lockedPath = null; diff --git a/src/main/java/net/szum123321/textile_backup/TextileBackup.java b/src/main/java/net/szum123321/textile_backup/TextileBackup.java index 81d514a..d1e313b 100644 --- a/src/main/java/net/szum123321/textile_backup/TextileBackup.java +++ b/src/main/java/net/szum123321/textile_backup/TextileBackup.java @@ -55,7 +55,7 @@ public class TextileBackup implements ModInitializer { ConfigHelper.updateInstance(AutoConfig.register(ConfigPOJO.class, JanksonConfigSerializer::new)); - ServerTickEvents.END_SERVER_TICK.register(new BackupScheduler()::tick); + ServerTickEvents.END_SERVER_TICK.register(BackupScheduler::tick); //Restart Executor Service in single-player ServerLifecycleEvents.SERVER_STARTING.register(server -> { @@ -63,6 +63,7 @@ public class TextileBackup implements ModInitializer { Globals.INSTANCE.updateTMPFSFlag(server); }); + //Wait 60s for already submited backups to finish. After that kill the bastards and run the one last if required ServerLifecycleEvents.SERVER_STOPPED.register(server -> { Globals.INSTANCE.shutdownQueueExecutor(60000); diff --git a/src/main/java/net/szum123321/textile_backup/core/ActionInitiator.java b/src/main/java/net/szum123321/textile_backup/core/ActionInitiator.java index f965874..07375b9 100644 --- a/src/main/java/net/szum123321/textile_backup/core/ActionInitiator.java +++ b/src/main/java/net/szum123321/textile_backup/core/ActionInitiator.java @@ -18,10 +18,13 @@ package net.szum123321.textile_backup.core; +/** + * Enum representing possible sources of action + */ public enum ActionInitiator { Player("Player", "by"), - ServerConsole("Server Console", "from"), - Timer("Timer", "by"), + ServerConsole("Server Console", "from"), //some/ting typed a command and it was not a player (command blocks and server console count) + Timer("Timer", "by"), //a.k.a scheduler Shutdown("Server Shutdown", "by"), Restore("Backup Restoration", "because of"), Null("Null (That shouldn't have happened)", "form"); diff --git a/src/main/java/net/szum123321/textile_backup/core/Cleanup.java b/src/main/java/net/szum123321/textile_backup/core/Cleanup.java index 7c90c74..77076e8 100644 --- a/src/main/java/net/szum123321/textile_backup/core/Cleanup.java +++ b/src/main/java/net/szum123321/textile_backup/core/Cleanup.java @@ -33,6 +33,9 @@ import java.time.ZoneOffset; import java.util.Objects; import java.util.stream.Stream; +/** + * Set of utility used for removing old backups + */ public class Cleanup { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); private final static ConfigHelper config = ConfigHelper.INSTANCE; @@ -55,7 +58,7 @@ public class Cleanup { } final int noToKeep = config.get().backupsToKeep > 0 ? config.get().backupsToKeep : Integer.MAX_VALUE; - final long maxSize = config.get().maxSize > 0 ? config.get().maxSize * 1024: Long.MAX_VALUE; + final long maxSize = config.get().maxSize > 0 ? config.get().maxSize * 1024: Long.MAX_VALUE; //max number of bytes to keep long[] counts = count(root); long n = counts[0], size = counts[1]; diff --git a/src/main/java/net/szum123321/textile_backup/core/RestoreableFile.java b/src/main/java/net/szum123321/textile_backup/core/RestoreableFile.java index 8684045..e9f41b4 100644 --- a/src/main/java/net/szum123321/textile_backup/core/RestoreableFile.java +++ b/src/main/java/net/szum123321/textile_backup/core/RestoreableFile.java @@ -40,6 +40,9 @@ import java.util.stream.Stream; import static java.nio.file.LinkOption.NOFOLLOW_LINKS; +/** + * This class parses backup files, extracting its creation time, format and possibly comment + */ public class RestoreableFile implements Comparable { private final Path file; private final ConfigPOJO.ArchiveFormat archiveFormat; @@ -53,6 +56,7 @@ public class RestoreableFile implements Comparable { this.comment = comment; } + //removes repetition of the files stream thingy with awfully large lambdas public static T applyOnFiles(Path root, T def, Consumer errorConsumer, Function, T> streamConsumer) { try (Stream stream = Files.list(root)) { return streamConsumer.apply(stream.flatMap(f -> RestoreableFile.build(f).stream())); diff --git a/src/main/java/net/szum123321/textile_backup/core/Utilities.java b/src/main/java/net/szum123321/textile_backup/core/Utilities.java index de88a1b..5482708 100644 --- a/src/main/java/net/szum123321/textile_backup/core/Utilities.java +++ b/src/main/java/net/szum123321/textile_backup/core/Utilities.java @@ -65,7 +65,6 @@ public class Utilities { .getWorldDirectory(World.OVERWORLD); } - public static void deleteDirectory(Path path) throws IOException { Files.walkFileTree(path, new SimplePathVisitor() { @Override diff --git a/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java b/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java index ad93166..63a3e3e 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java @@ -21,12 +21,9 @@ package net.szum123321.textile_backup.core.create; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.util.Util; import net.szum123321.textile_backup.core.ActionInitiator; import org.jetbrains.annotations.NotNull; -import java.util.UUID; - public record BackupContext(@NotNull MinecraftServer server, ServerCommandSource commandSource, ActionInitiator initiator, @@ -103,8 +100,7 @@ public record BackupContext(@NotNull MinecraftServer server, if (server == null) { if (commandSource != null) setServer(commandSource.getServer()); - else - throw new RuntimeException("Neither MinecraftServer or ServerCommandSource were provided!"); + else throw new RuntimeException("Neither MinecraftServer or ServerCommandSource were provided!"); } return new BackupContext(server, commandSource, initiator, save, comment); diff --git a/src/main/java/net/szum123321/textile_backup/core/create/BackupScheduler.java b/src/main/java/net/szum123321/textile_backup/core/create/BackupScheduler.java index 6ce816a..c4d7e1b 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupScheduler.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/BackupScheduler.java @@ -25,24 +25,32 @@ import net.szum123321.textile_backup.core.ActionInitiator; import java.time.Instant; +/** + * Runs backup on a preset interval + *
+ * The important thing to note:
+ * In the case that doBackupsOnEmptyServer == false and there have been made backups with players online, + * then everyone left the backup that was scheduled with player is still going to run. So it might appear as though there + * has been made backup with no players online despite the config. This is the expected behaviour + *
+ * Furthermore, it uses system time + */ public class BackupScheduler { private final static ConfigHelper config = ConfigHelper.INSTANCE; - private boolean scheduled; - private long nextBackup; + //Scheduled flag tells whether we have decided to run another backup + private static boolean scheduled = false; + private static long nextBackup = - 1; - public BackupScheduler() { - scheduled = false; - nextBackup = -1; - } - - public void tick(MinecraftServer server) { + public static void tick(MinecraftServer server) { if(config.get().backupInterval < 1) return; long now = Instant.now().getEpochSecond(); if(config.get().doBackupsOnEmptyServer || server.getPlayerManager().getCurrentPlayerCount() > 0) { + //Either just run backup with no one playing or there's at least one player if(scheduled) { if(nextBackup <= now) { + //It's time to run Globals.INSTANCE.getQueueExecutor().submit( MakeBackupRunnableFactory.create( BackupContext.Builder @@ -57,11 +65,15 @@ public class BackupScheduler { nextBackup = now + config.get().backupInterval; } } else { + //Either server just started or a new player joined after the last backup has finished + //So let's schedule one some time from now nextBackup = now + config.get().backupInterval; scheduled = true; } } else if(!config.get().doBackupsOnEmptyServer && server.getPlayerManager().getCurrentPlayerCount() == 0) { + //Do the final backup. No one's on-line and doBackupsOnEmptyServer == false if(scheduled && nextBackup <= now) { + //Verify we hadn't done the final one and its time to do so Globals.INSTANCE.getQueueExecutor().submit( MakeBackupRunnableFactory.create( BackupContext.Builder diff --git a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java index 8bfa995..7b6adee 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java @@ -37,6 +37,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; +/** + * The actual object responsible for creating the backup + */ public class MakeBackupRunnable implements Runnable { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); private final static ConfigHelper config = ConfigHelper.INSTANCE; @@ -87,7 +90,7 @@ public class MakeBackupRunnable implements Runnable { log.trace("Using PARALLEL Zip Compressor. Threads: {}", coreCount); } else { ZipCompressor.getInstance().createArchive(world, outFile, context, coreCount); - log.trace("Using REGULAR Zip Compressor. Threads: {}"); + log.trace("Using REGULAR Zip Compressor."); } } case BZIP2 -> ParallelBZip2Compressor.getInstance().createArchive(world, outFile, context, coreCount); diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java index 744a89e..45e5f65 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java @@ -33,6 +33,9 @@ import java.time.Instant; import java.util.concurrent.ExecutionException; import java.util.stream.Stream; +/** + * Basic abstract class representing directory compressor + */ public abstract class AbstractCompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); @@ -88,7 +91,7 @@ public abstract class AbstractCompressor { protected abstract void addEntry(Path file, String entryName, OutputStream arc) throws IOException; protected void finish(OutputStream arc) throws InterruptedException, ExecutionException, IOException { - //Basically this function is only needed for the ParallelZipCompressor to write out ParallelScatterZipCreator + //This function is only needed for the ParallelZipCompressor to write out ParallelScatterZipCreator } protected void close() { diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java index 2f3e207..be798b4 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java @@ -35,6 +35,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +//TODO: Verify backup's validity? public class RestoreBackupRunnable implements Runnable { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); private final static ConfigHelper config = ConfigHelper.INSTANCE; diff --git a/src/main/java/net/szum123321/textile_backup/mixin/DedicatedServerWatchdogMixin.java b/src/main/java/net/szum123321/textile_backup/mixin/DedicatedServerWatchdogMixin.java index 2b9f0bb..415939c 100644 --- a/src/main/java/net/szum123321/textile_backup/mixin/DedicatedServerWatchdogMixin.java +++ b/src/main/java/net/szum123321/textile_backup/mixin/DedicatedServerWatchdogMixin.java @@ -25,6 +25,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyVariable; +/** + * This mixin should numb Watchdog while a backup runs. + * If works as intended solves issues with watchdog errors + */ @Mixin(DedicatedServerWatchdog.class) public class DedicatedServerWatchdogMixin {