diff --git a/src/main/java/net/szum123321/textile_backup/Globals.java b/src/main/java/net/szum123321/textile_backup/Globals.java index 62f04d3..26beea8 100644 --- a/src/main/java/net/szum123321/textile_backup/Globals.java +++ b/src/main/java/net/szum123321/textile_backup/Globals.java @@ -23,7 +23,6 @@ import net.szum123321.textile_backup.core.digest.BalticHash; import net.szum123321.textile_backup.core.digest.Hash; import net.szum123321.textile_backup.core.Utilities; -import net.szum123321.textile_backup.core.create.MakeBackupRunnable; import net.szum123321.textile_backup.core.restore.AwaitThread; import org.apache.commons.io.FileUtils; @@ -70,8 +69,8 @@ public class Globals { if(!executorService.awaitTermination(timeout, TimeUnit.MICROSECONDS)) { log.error("Timeout occurred while waiting for currently running backups to finish!"); executorService.shutdownNow().stream() - .filter(r -> r instanceof MakeBackupRunnable) - .map(r -> (MakeBackupRunnable)r) + // .filter(r -> r instanceof ExecutableBackup) + // .map(r -> (ExecutableBackup)r) .forEach(r -> log.error("Dropping: {}", r.toString())); if(!executorService.awaitTermination(1000, TimeUnit.MICROSECONDS)) log.error("Couldn't shut down the executor!"); diff --git a/src/main/java/net/szum123321/textile_backup/TextileBackup.java b/src/main/java/net/szum123321/textile_backup/TextileBackup.java index 853aa3e..4d10e03 100644 --- a/src/main/java/net/szum123321/textile_backup/TextileBackup.java +++ b/src/main/java/net/szum123321/textile_backup/TextileBackup.java @@ -39,9 +39,8 @@ import net.szum123321.textile_backup.commands.restore.RestoreBackupCommand; import net.szum123321.textile_backup.config.ConfigHelper; import net.szum123321.textile_backup.config.ConfigPOJO; import net.szum123321.textile_backup.core.ActionInitiator; -import net.szum123321.textile_backup.core.create.BackupContext; import net.szum123321.textile_backup.core.create.BackupScheduler; -import net.szum123321.textile_backup.core.create.MakeBackupRunnableFactory; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import net.szum123321.textile_backup.test.BalticHashTest; public class TextileBackup implements ModInitializer { @@ -82,14 +81,14 @@ public class TextileBackup implements ModInitializer { if (config.get().shutdownBackup && Globals.INSTANCE.globalShutdownBackupFlag.get()) { try { - MakeBackupRunnableFactory.create( - BackupContext.Builder + ExecutableBackup.Builder .newBackupContextBuilder() .setServer(server) .setInitiator(ActionInitiator.Shutdown) .setComment("shutdown") + .announce() .build() - ).call(); + .call(); } catch (Exception ignored) {} } }); diff --git a/src/main/java/net/szum123321/textile_backup/TextileLogger.java b/src/main/java/net/szum123321/textile_backup/TextileLogger.java index 2e77da9..0a38389 100644 --- a/src/main/java/net/szum123321/textile_backup/TextileLogger.java +++ b/src/main/java/net/szum123321/textile_backup/TextileLogger.java @@ -23,7 +23,7 @@ import net.minecraft.text.Text; import net.minecraft.text.MutableText; import net.minecraft.util.Formatting; import net.szum123321.textile_backup.core.Utilities; -import net.szum123321.textile_backup.core.create.BackupContext; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -112,7 +112,7 @@ public class TextileLogger { sendFeedback(Level.INFO, source, msg, args); } - public void sendInfo(BackupContext context, String msg, Object... args) { + public void sendInfo(ExecutableBackup context, String msg, Object... args) { sendInfo(context.commandSource(), msg, args); } @@ -120,7 +120,8 @@ public class TextileLogger { sendFeedback(Level.ERROR, source, msg, args); } - public void sendError(BackupContext context, String msg, Object... args) { + + public void sendError(ExecutableBackup context, String msg, Object... args) { sendError(context.commandSource(), msg, args); } @@ -134,7 +135,7 @@ public class TextileLogger { sendToPlayerAndLog(Level.INFO, source, msg, args); } - public void sendInfoAL(BackupContext context, String msg, Object... args) { + public void sendInfoAL(ExecutableBackup context, String msg, Object... args) { sendInfoAL(context.commandSource(), msg, args); } @@ -142,7 +143,7 @@ public class TextileLogger { sendToPlayerAndLog(Level.ERROR, source, msg, args); } - public void sendErrorAL(BackupContext context, String msg, Object... args) { + public void sendErrorAL(ExecutableBackup context, String msg, Object... args) { sendErrorAL(context.commandSource(), msg, args); } } diff --git a/src/main/java/net/szum123321/textile_backup/commands/create/StartBackupCommand.java b/src/main/java/net/szum123321/textile_backup/commands/create/StartBackupCommand.java index 1ec744f..7964c5a 100644 --- a/src/main/java/net/szum123321/textile_backup/commands/create/StartBackupCommand.java +++ b/src/main/java/net/szum123321/textile_backup/commands/create/StartBackupCommand.java @@ -25,8 +25,7 @@ import net.minecraft.server.command.ServerCommandSource; import net.szum123321.textile_backup.Globals; import net.szum123321.textile_backup.TextileBackup; import net.szum123321.textile_backup.TextileLogger; -import net.szum123321.textile_backup.core.create.BackupContext; -import net.szum123321.textile_backup.core.create.MakeBackupRunnableFactory; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import javax.annotation.Nullable; @@ -42,15 +41,13 @@ public class StartBackupCommand { private static int execute(ServerCommandSource source, @Nullable String comment) { Globals.INSTANCE.getQueueExecutor().submit( - MakeBackupRunnableFactory.create( - BackupContext.Builder - .newBackupContextBuilder() - .setCommandSource(source) - .setComment(comment) - .guessInitiator() - .saveServer() - .build() - ) + ExecutableBackup.Builder + .newBackupContextBuilder() + .setCommandSource(source) + .setComment(comment) + .guessInitiator() + .saveServer() + .build() ); return 1; 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 deleted file mode 100644 index d626695..0000000 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * A simple backup mod for Fabric - * Copyright (C) 2022 Szum123321 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.szum123321.textile_backup.core.create; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.ServerCommandSource; -import net.szum123321.textile_backup.core.ActionInitiator; -import net.szum123321.textile_backup.core.Utilities; -import org.jetbrains.annotations.NotNull; - -import java.time.LocalDateTime; -import java.util.NoSuchElementException; - -public record BackupContext(@NotNull MinecraftServer server, - ServerCommandSource commandSource, - ActionInitiator initiator, - boolean save, - boolean cleanup, - String comment, - LocalDateTime startDate) { - - public boolean startedByPlayer() { - return initiator == ActionInitiator.Player; - } - - public boolean shouldSave() { - return save; - } - - public static class Builder { - private MinecraftServer server; - private ServerCommandSource commandSource; - private ActionInitiator initiator; - private boolean save; - private boolean cleanup; - private String comment; - - private boolean guessInitiator; - - public Builder() { - this.server = null; - this.commandSource = null; - this.initiator = null; - this.save = false; - cleanup = true; //defaults - this.comment = null; - - guessInitiator = false; - } - - public static Builder newBackupContextBuilder() { - return new Builder(); - } - - public Builder setCommandSource(ServerCommandSource commandSource) { - this.commandSource = commandSource; - return this; - } - - public Builder setServer(MinecraftServer server) { - this.server = server; - return this; - } - - public Builder setInitiator(ActionInitiator initiator) { - this.initiator = initiator; - return this; - } - - public Builder setComment(String comment) { - this.comment = comment; - return this; - } - - public Builder guessInitiator() { - this.guessInitiator = true; - return this; - } - - public Builder saveServer() { - this.save = true; - return this; - } - - public Builder dontCleanup() { - this.cleanup = false; - return this; - } - - public BackupContext build() { - if (guessInitiator) { - initiator = Utilities.wasSentByPlayer(commandSource) ? ActionInitiator.Player : ActionInitiator.ServerConsole; - } else if (initiator == null) throw new NoSuchElementException("No initiator provided!"); - - if (server == null) { - if (commandSource != null) setServer(commandSource.getServer()); - else throw new RuntimeException("Neither MinecraftServer or ServerCommandSource were provided!"); - } - - return new BackupContext(server, commandSource, initiator, save, cleanup, comment, LocalDateTime.now()); - } - } -} 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 3359db9..55a13f3 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 @@ -53,14 +53,13 @@ public class BackupScheduler { if(nextBackup <= now) { //It's time to run Globals.INSTANCE.getQueueExecutor().submit( - MakeBackupRunnableFactory.create( - BackupContext.Builder - .newBackupContextBuilder() - .setServer(server) - .setInitiator(ActionInitiator.Timer) - .saveServer() - .build() - ) + ExecutableBackup.Builder + .newBackupContextBuilder() + .setServer(server) + .setInitiator(ActionInitiator.Timer) + .saveServer() + .announce() + .build() ); nextBackup = now + config.get().backupInterval; @@ -76,14 +75,13 @@ public class BackupScheduler { if(scheduled && nextBackup <= now) { //Verify we hadn't done the final one, and it's time to do so Globals.INSTANCE.getQueueExecutor().submit( - MakeBackupRunnableFactory.create( - BackupContext.Builder - .newBackupContextBuilder() - .setServer(server) - .setInitiator(ActionInitiator.Timer) - .saveServer() - .build() - ) + ExecutableBackup.Builder + .newBackupContextBuilder() + .setServer(server) + .setInitiator(ActionInitiator.Timer) + .saveServer() + .announce() + .build() ); scheduled = false; diff --git a/src/main/java/net/szum123321/textile_backup/core/create/ExecutableBackup.java b/src/main/java/net/szum123321/textile_backup/core/create/ExecutableBackup.java new file mode 100644 index 0000000..9f5071f --- /dev/null +++ b/src/main/java/net/szum123321/textile_backup/core/create/ExecutableBackup.java @@ -0,0 +1,232 @@ +package net.szum123321.textile_backup.core.create; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; +import net.szum123321.textile_backup.Globals; +import net.szum123321.textile_backup.TextileBackup; +import net.szum123321.textile_backup.TextileLogger; +import net.szum123321.textile_backup.config.ConfigHelper; +import net.szum123321.textile_backup.core.ActionInitiator; +import net.szum123321.textile_backup.core.Cleanup; +import net.szum123321.textile_backup.core.Utilities; +import net.szum123321.textile_backup.core.create.compressors.ParallelZipCompressor; +import net.szum123321.textile_backup.core.create.compressors.ZipCompressor; +import net.szum123321.textile_backup.core.create.compressors.tar.AbstractTarArchiver; +import net.szum123321.textile_backup.core.create.compressors.tar.ParallelGzipCompressor; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.NoSuchElementException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; + +public record ExecutableBackup(@NotNull MinecraftServer server, + ServerCommandSource commandSource, + ActionInitiator initiator, + boolean save, + boolean cleanup, + String comment, + LocalDateTime startDate) implements Callable { + + private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); + private final static ConfigHelper config = ConfigHelper.INSTANCE; + + public boolean startedByPlayer() { + return initiator == ActionInitiator.Player; + } + + public void announce() { + if(config.get().broadcastBackupStart) { + Utilities.notifyPlayers(server, + "Warning! Server backup will begin shortly. You may experience some lag." + ); + } else { + log.sendInfoAL(this, "Warning! Server backup will begin shortly. You may experience some lag."); + } + + StringBuilder builder = new StringBuilder(); + + builder.append("Backup started "); + + builder.append(initiator.getPrefix()); + + if(startedByPlayer()) + builder.append(commandSource.getDisplayName().getString()); + else + builder.append(initiator.getName()); + + builder.append(" on: "); + builder.append(Utilities.getDateTimeFormatter().format(LocalDateTime.now())); + + log.info(builder.toString()); + } + @Override + public Void call() throws IOException, ExecutionException, InterruptedException { + if (save) { //save the world + log.sendInfoAL(this, "Saving server..."); + server.saveAll(true, true, false); + } + + Path outFile = Utilities.getBackupRootPath(Utilities.getLevelName(server)).resolve(getFileName()); + + log.trace("Outfile is: {}", outFile); + + try { + //I think I should synchronise these two next calls... + Utilities.disableWorldSaving(server); + Globals.INSTANCE.disableWatchdog = true; + + Globals.INSTANCE.updateTMPFSFlag(server); + + log.sendInfoAL(this, "Starting backup"); + + Path world = Utilities.getWorldFolder(server); + + log.trace("Minecraft world is: {}", world); + + Files.createDirectories(outFile.getParent()); + Files.createFile(outFile); + + int coreCount; + + if (config.get().compressionCoreCountLimit <= 0) coreCount = Runtime.getRuntime().availableProcessors(); + else + coreCount = Math.min(config.get().compressionCoreCountLimit, Runtime.getRuntime().availableProcessors()); + + log.trace("Running compression on {} threads. Available cores: {}", coreCount, Runtime.getRuntime().availableProcessors()); + + switch (config.get().format) { + case ZIP -> { + if (coreCount > 1 && !Globals.INSTANCE.disableTMPFS()) { + log.trace("Using PARALLEL Zip Compressor. Threads: {}", coreCount); + ParallelZipCompressor.getInstance().createArchive(world, outFile, this, coreCount); + } else { + log.trace("Using REGULAR Zip Compressor."); + ZipCompressor.getInstance().createArchive(world, outFile, this, coreCount); + } + } + case GZIP -> ParallelGzipCompressor.getInstance().createArchive(world, outFile, this, coreCount); + case TAR -> new AbstractTarArchiver().createArchive(world, outFile, this, coreCount); + } + + if(cleanup) new Cleanup(commandSource, Utilities.getLevelName(server)).call(); + + if (config.get().broadcastBackupDone) Utilities.notifyPlayers(server, "Done!"); + else log.sendInfoAL(this, "Done!"); + + } catch (Throwable e) { + //ExecutorService swallows exception, so I need to catch everything + log.error("An exception occurred when trying to create new backup file!", e); + + if (ConfigHelper.INSTANCE.get().integrityVerificationMode.isStrict()) { + try { + Files.delete(outFile); + } catch (IOException ex) { + log.error("An exception occurred while trying go delete: {}", outFile, ex); + } + } + + if (initiator == ActionInitiator.Player) + log.sendError(this, "An exception occurred when trying to create new backup file!"); + + throw e; + } finally { + Utilities.enableWorldSaving(server); + Globals.INSTANCE.disableWatchdog = false; + } + + return null; + } + + private String getFileName() { + return Utilities.getDateTimeFormatter().format(startDate) + + (comment != null ? "#" + comment.replaceAll("[\\\\/:*?\"<>|#]", "") : "") + + config.get().format.getCompleteString(); + } + public static class Builder { + private MinecraftServer server; + private ServerCommandSource commandSource; + private ActionInitiator initiator; + private boolean save; + private boolean cleanup; + private String comment; + private boolean announce; + + private boolean guessInitiator; + + public Builder() { + this.server = null; + this.commandSource = null; + this.initiator = null; + this.save = false; + cleanup = true; //defaults + this.comment = null; + this.announce = false; + + guessInitiator = false; + } + + public static ExecutableBackup.Builder newBackupContextBuilder() { + return new ExecutableBackup.Builder(); + } + + public ExecutableBackup.Builder setCommandSource(ServerCommandSource commandSource) { + this.commandSource = commandSource; + return this; + } + + public ExecutableBackup.Builder setServer(MinecraftServer server) { + this.server = server; + return this; + } + + public ExecutableBackup.Builder setInitiator(ActionInitiator initiator) { + this.initiator = initiator; + return this; + } + + public ExecutableBackup.Builder setComment(String comment) { + this.comment = comment; + return this; + } + + public ExecutableBackup.Builder guessInitiator() { + this.guessInitiator = true; + return this; + } + + public ExecutableBackup.Builder saveServer() { + this.save = true; + return this; + } + + public ExecutableBackup.Builder noCleanup() { + this.cleanup = false; + return this; + } + + public ExecutableBackup.Builder announce() { + this.announce = true; + return this; + } + + public ExecutableBackup build() { + if (guessInitiator) { + initiator = Utilities.wasSentByPlayer(commandSource) ? ActionInitiator.Player : ActionInitiator.ServerConsole; + } else if (initiator == null) throw new NoSuchElementException("No initiator provided!"); + + if (server == null) { + if (commandSource != null) setServer(commandSource.getServer()); + else throw new RuntimeException("Neither MinecraftServer or ServerCommandSource were provided!"); + } + + ExecutableBackup v = new ExecutableBackup(server, commandSource, initiator, save, cleanup, comment, LocalDateTime.now()); + + if(announce) v.announce(); + return v; + } + } +} 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 deleted file mode 100644 index 03d98a6..0000000 --- a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * A simple backup mod for Fabric - * Copyright (C) 2022 Szum123321 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.szum123321.textile_backup.core.create; - -import net.szum123321.textile_backup.Globals; -import net.szum123321.textile_backup.TextileBackup; -import net.szum123321.textile_backup.TextileLogger; -import net.szum123321.textile_backup.config.ConfigHelper; -import net.szum123321.textile_backup.core.ActionInitiator; -import net.szum123321.textile_backup.core.Cleanup; -import net.szum123321.textile_backup.core.Utilities; -import net.szum123321.textile_backup.core.create.compressors.ParallelZipCompressor; -import net.szum123321.textile_backup.core.create.compressors.ZipCompressor; -import net.szum123321.textile_backup.core.create.compressors.tar.AbstractTarArchiver; -import net.szum123321.textile_backup.core.create.compressors.tar.ParallelBZip2Compressor; -import net.szum123321.textile_backup.core.create.compressors.tar.ParallelGzipCompressor; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; - -/** - * The actual object responsible for creating the backup - */ -public class MakeBackupRunnable implements Callable { - private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - private final static ConfigHelper config = ConfigHelper.INSTANCE; - - private final BackupContext context; - - public MakeBackupRunnable(BackupContext context) { - this.context = context; - } - - @Override - public Void call() throws IOException, ExecutionException, InterruptedException { - Path outFile = Utilities.getBackupRootPath(Utilities.getLevelName(context.server())).resolve(getFileName()); - - log.trace("Outfile is: {}", outFile); - - try { - //I think I should synchronise these two next calls... - Utilities.disableWorldSaving(context.server()); - Globals.INSTANCE.disableWatchdog = true; - - Globals.INSTANCE.updateTMPFSFlag(context.server()); - - log.sendInfoAL(context, "Starting backup"); - - Path world = Utilities.getWorldFolder(context.server()); - - log.trace("Minecraft world is: {}", world); - - Files.createDirectories(outFile.getParent()); - Files.createFile(outFile); - - int coreCount; - - if (config.get().compressionCoreCountLimit <= 0) coreCount = Runtime.getRuntime().availableProcessors(); - else - coreCount = Math.min(config.get().compressionCoreCountLimit, Runtime.getRuntime().availableProcessors()); - - log.trace("Running compression on {} threads. Available cores: {}", coreCount, Runtime.getRuntime().availableProcessors()); - - switch (config.get().format) { - case ZIP -> { - if (coreCount > 1 && !Globals.INSTANCE.disableTMPFS()) { - log.trace("Using PARALLEL Zip Compressor. Threads: {}", coreCount); - ParallelZipCompressor.getInstance().createArchive(world, outFile, context, coreCount); - } else { - log.trace("Using REGULAR Zip Compressor."); - ZipCompressor.getInstance().createArchive(world, outFile, context, coreCount); - } - } - case BZIP2 -> ParallelBZip2Compressor.getInstance().createArchive(world, outFile, context, coreCount); - case GZIP -> ParallelGzipCompressor.getInstance().createArchive(world, outFile, context, coreCount); - /* case LZMA -> new AbstractTarArchiver() { - protected OutputStream getCompressorOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException { - return new LZMACompressorOutputStream(stream); - } - }.createArchive(world, outFile, context, coreCount);*/ - case TAR -> new AbstractTarArchiver().createArchive(world, outFile, context, coreCount); - } - - if(context.cleanup()) - new Cleanup(context.commandSource(), Utilities.getLevelName(context.server())).call(); - - if (config.get().broadcastBackupDone) Utilities.notifyPlayers(context.server(), "Done!"); - else log.sendInfoAL(context, "Done!"); - - } catch (Throwable e) { - //ExecutorService swallows exception, so I need to catch everything - log.error("An exception occurred when trying to create new backup file!", e); - - if (ConfigHelper.INSTANCE.get().integrityVerificationMode.isStrict()) { - try { - Files.delete(outFile); - } catch (IOException ex) { - log.error("An exception occurred while trying go delete: {}", outFile, ex); - } - } - - if (context.initiator() == ActionInitiator.Player) - log.sendError(context, "An exception occurred when trying to create new backup file!"); - - throw e; - } finally { - Utilities.enableWorldSaving(context.server()); - Globals.INSTANCE.disableWatchdog = false; - } - - return null; - } - - private String getFileName() { - return Utilities.getDateTimeFormatter().format(context.startDate()) + - (context.comment() != null ? "#" + context.comment().replaceAll("[\\\\/:*?\"<>|#]", "") : "") + - config.get().format.getCompleteString(); - } -} diff --git a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnableFactory.java b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnableFactory.java deleted file mode 100644 index 099d17c..0000000 --- a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnableFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * A simple backup mod for Fabric - * Copyright (C) 2022 Szum123321 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.szum123321.textile_backup.core.create; - -import net.szum123321.textile_backup.TextileBackup; -import net.szum123321.textile_backup.TextileLogger; -import net.szum123321.textile_backup.config.ConfigHelper; -import net.szum123321.textile_backup.core.Utilities; - -import java.time.LocalDateTime; -import java.util.concurrent.Callable; - -public class MakeBackupRunnableFactory { - private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - private final static ConfigHelper config = ConfigHelper.INSTANCE; - - public static Callable create(BackupContext ctx) { - if(config.get().broadcastBackupStart) { - Utilities.notifyPlayers(ctx.server(), - "Warning! Server backup will begin shortly. You may experience some lag." - ); - } else { - log.sendInfoAL(ctx, "Warning! Server backup will begin shortly. You may experience some lag."); - } - - StringBuilder builder = new StringBuilder(); - - builder.append("Backup started "); - - builder.append(ctx.initiator().getPrefix()); - - if(ctx.startedByPlayer()) - builder.append(ctx.commandSource().getDisplayName().getString()); - else - builder.append(ctx.initiator().getName()); - - builder.append(" on: "); - builder.append(Utilities.getDateTimeFormatter().format(LocalDateTime.now())); - - log.info(builder.toString()); - - if (ctx.shouldSave()) { - log.sendInfoAL(ctx, "Saving server..."); - - ctx.server().saveAll(true, true, false); - } - - return new MakeBackupRunnable(ctx); - } -} 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 f5f6815..108c6e5 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 @@ -23,8 +23,8 @@ import net.szum123321.textile_backup.TextileBackup; import net.szum123321.textile_backup.TextileLogger; import net.szum123321.textile_backup.config.ConfigHelper; import net.szum123321.textile_backup.core.*; -import net.szum123321.textile_backup.core.create.BackupContext; import net.szum123321.textile_backup.core.create.BrokenFileHandler; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import net.szum123321.textile_backup.core.create.FileInputStreamSupplier; import net.szum123321.textile_backup.core.create.InputSupplier; import net.szum123321.textile_backup.core.digest.FileTreeHashBuilder; @@ -44,7 +44,7 @@ import java.util.stream.Stream; public abstract class AbstractCompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - public void createArchive(Path inputFile, Path outputFile, BackupContext ctx, int coreLimit) throws IOException, ExecutionException, InterruptedException { + public void createArchive(Path inputFile, Path outputFile, ExecutableBackup ctx, int coreLimit) throws IOException, ExecutionException, InterruptedException { Instant start = Instant.now(); BrokenFileHandler brokenFileHandler = new BrokenFileHandler(); //Basically a hashmap storing files and their respective exceptions @@ -106,7 +106,7 @@ public abstract class AbstractCompressor { log.sendInfoAL(ctx, "Compression took: {} seconds.", Utilities.formatDuration(Duration.between(start, Instant.now()))); } - protected abstract OutputStream createArchiveOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException; + protected abstract OutputStream createArchiveOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) throws IOException; protected abstract void addEntry(InputSupplier inputSupplier, OutputStream arc) throws IOException; protected void finish(OutputStream arc) throws InterruptedException, ExecutionException, IOException { diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java index 3632179..7ed67a1 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java @@ -21,7 +21,7 @@ package net.szum123321.textile_backup.core.create.compressors; import net.szum123321.textile_backup.TextileBackup; import net.szum123321.textile_backup.TextileLogger; import net.szum123321.textile_backup.core.NoSpaceLeftOnDeviceException; -import net.szum123321.textile_backup.core.create.BackupContext; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import net.szum123321.textile_backup.core.create.InputSupplier; import org.apache.commons.compress.archivers.zip.*; @@ -61,7 +61,7 @@ public class ParallelZipCompressor extends ZipCompressor { } @Override - protected OutputStream createArchiveOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) { + protected OutputStream createArchiveOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) { scatterZipCreator = new ParallelScatterZipCreator(Executors.newFixedThreadPool(coreLimit)); return super.createArchiveOutputStream(stream, ctx, coreLimit); } diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java index 5a39bab..a1b224b 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java @@ -20,7 +20,7 @@ package net.szum123321.textile_backup.core.create.compressors; import net.szum123321.textile_backup.config.ConfigHelper; import net.szum123321.textile_backup.core.Utilities; -import net.szum123321.textile_backup.core.create.BackupContext; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import net.szum123321.textile_backup.core.create.InputSupplier; import org.apache.commons.compress.archivers.zip.Zip64Mode; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; @@ -43,7 +43,7 @@ public class ZipCompressor extends AbstractCompressor { } @Override - protected OutputStream createArchiveOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) { + protected OutputStream createArchiveOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) { ZipArchiveOutputStream arc = new ZipArchiveOutputStream(stream); arc.setMethod(ZipArchiveOutputStream.DEFLATED); diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java index 4ae84a3..52e86e5 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java @@ -18,7 +18,7 @@ package net.szum123321.textile_backup.core.create.compressors.tar; -import net.szum123321.textile_backup.core.create.BackupContext; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import net.szum123321.textile_backup.core.create.compressors.AbstractCompressor; import net.szum123321.textile_backup.core.create.InputSupplier; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; @@ -28,12 +28,12 @@ import org.apache.commons.compress.utils.IOUtils; import java.io.*; public class AbstractTarArchiver extends AbstractCompressor { - protected OutputStream getCompressorOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException { + protected OutputStream getCompressorOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) throws IOException { return stream; } @Override - protected OutputStream createArchiveOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException { + protected OutputStream createArchiveOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) throws IOException { TarArchiveOutputStream tar = new TarArchiveOutputStream(getCompressorOutputStream(stream, ctx, coreLimit)); tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); tar.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelBZip2Compressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelBZip2Compressor.java index 76d96fe..2bd2840 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelBZip2Compressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelBZip2Compressor.java @@ -18,7 +18,7 @@ package net.szum123321.textile_backup.core.create.compressors.tar; -import net.szum123321.textile_backup.core.create.BackupContext; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import org.at4j.comp.bzip2.BZip2OutputStream; import org.at4j.comp.bzip2.BZip2OutputStreamSettings; @@ -30,7 +30,7 @@ public class ParallelBZip2Compressor extends AbstractTarArchiver { } @Override - protected OutputStream getCompressorOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException { + protected OutputStream getCompressorOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) throws IOException { return new BZip2OutputStream(stream, new BZip2OutputStreamSettings().setNumberOfEncoderThreads(coreLimit)); } } \ No newline at end of file diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelGzipCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelGzipCompressor.java index 0a59638..94b9da6 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelGzipCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/ParallelGzipCompressor.java @@ -18,7 +18,7 @@ package net.szum123321.textile_backup.core.create.compressors.tar; -import net.szum123321.textile_backup.core.create.BackupContext; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import org.anarres.parallelgzip.ParallelGZIPOutputStream; import java.io.*; @@ -33,7 +33,7 @@ public class ParallelGzipCompressor extends AbstractTarArchiver { } @Override - protected OutputStream getCompressorOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException { + protected OutputStream getCompressorOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) throws IOException { executorService = Executors.newFixedThreadPool(coreLimit); return new ParallelGZIPOutputStream(stream, executorService); 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 6f705eb..b3520fc 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 @@ -26,8 +26,7 @@ import net.szum123321.textile_backup.config.ConfigPOJO; import net.szum123321.textile_backup.core.ActionInitiator; import net.szum123321.textile_backup.core.CompressionStatus; import net.szum123321.textile_backup.core.Utilities; -import net.szum123321.textile_backup.core.create.BackupContext; -import net.szum123321.textile_backup.core.create.MakeBackupRunnableFactory; +import net.szum123321.textile_backup.core.create.ExecutableBackup; import net.szum123321.textile_backup.core.restore.decompressors.GenericTarDecompressor; import net.szum123321.textile_backup.core.restore.decompressors.ZipDecompressor; import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor; @@ -78,20 +77,19 @@ public class RestoreBackupRunnable implements Runnable { ctx.server().getThread().join(); //wait for server thread to die and save all its state if(config.get().backupOldWorlds) { - return MakeBackupRunnableFactory.create ( - BackupContext.Builder + return ExecutableBackup.Builder .newBackupContextBuilder() .setServer(ctx.server()) .setInitiator(ActionInitiator.Restore) - .dontCleanup() + .noCleanup() .setComment("Old_World" + (ctx.comment() != null ? "_" + ctx.comment() : "")) - .build() - ).call(); + .announce() + .build().call(); } - return null; }); + //run the thread. new Thread(waitForShutdown, "Server shutdown wait thread").start(); try { @@ -106,7 +104,7 @@ public class RestoreBackupRunnable implements Runnable { log.info("Waiting for server to fully terminate..."); - //locks until the backup is finished + //locks until the backup is finished and the server is dead waitForShutdown.get(); Optional errorMsg; @@ -127,8 +125,8 @@ public class RestoreBackupRunnable implements Runnable { if (errorMsg.isEmpty()) log.info("Backup valid. Restoring"); else log.info("Backup is damaged, but verification is disabled [{}]. Restoring", errorMsg.get()); - ((MinecraftServerSessionAccessor) ctx.server()) - .getSession().close(); + //Disables write lock to override world file + ((MinecraftServerSessionAccessor) ctx.server()).getSession().close(); Utilities.deleteDirectory(worldFile); Files.move(tmp, worldFile);