From dbb9a71749f31d18a83f4ea5b3e4daf1b398e8a6 Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Fri, 25 Nov 2022 09:54:44 +0100 Subject: [PATCH] Moved around error handling. LocalDateTime is now passed with BackupContext. Replaced equals method with matches in ParallelZipCompressor.SimpleStackTraceElement to avert warning. --- .../szum123321/textile_backup/Globals.java | 4 +- .../textile_backup/config/ConfigPOJO.java | 4 +- .../core/CompressionStatus.java | 18 ++++++- .../core/create/BackupContext.java | 7 ++- .../core/create/MakeBackupRunnable.java | 26 ++++++---- .../compressors/AbstractCompressor.java | 47 ++++++++----------- .../compressors/ParallelZipCompressor.java | 16 ++----- 7 files changed, 66 insertions(+), 56 deletions(-) diff --git a/src/main/java/net/szum123321/textile_backup/Globals.java b/src/main/java/net/szum123321/textile_backup/Globals.java index 8d33251..b906076 100644 --- a/src/main/java/net/szum123321/textile_backup/Globals.java +++ b/src/main/java/net/szum123321/textile_backup/Globals.java @@ -84,8 +84,8 @@ public class Globals { public Optional getLockedFile() { return Optional.ofNullable(lockedPath); } public void setLockedFile(Path p) { lockedPath = p; } - public boolean disableTMPFS() { return disableTMPFiles; } - public void updateTMPFSFlag(MinecraftServer server) { + public synchronized boolean disableTMPFS() { return disableTMPFiles; } + public synchronized void updateTMPFSFlag(MinecraftServer server) { disableTMPFiles = false; Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir")); if( diff --git a/src/main/java/net/szum123321/textile_backup/config/ConfigPOJO.java b/src/main/java/net/szum123321/textile_backup/config/ConfigPOJO.java index be45b40..439b1d2 100644 --- a/src/main/java/net/szum123321/textile_backup/config/ConfigPOJO.java +++ b/src/main/java/net/szum123321/textile_backup/config/ConfigPOJO.java @@ -188,7 +188,9 @@ public class ConfigPOJO implements ConfigData { public enum ErrorHandlingMode { STRICT, PERMISSIBLE, - VERY_PERMISSIBLE + VERY_PERMISSIBLE; + + public boolean isStrict() { return this == STRICT; } } public enum ArchiveFormat { diff --git a/src/main/java/net/szum123321/textile_backup/core/CompressionStatus.java b/src/main/java/net/szum123321/textile_backup/core/CompressionStatus.java index c16fb90..c21245c 100644 --- a/src/main/java/net/szum123321/textile_backup/core/CompressionStatus.java +++ b/src/main/java/net/szum123321/textile_backup/core/CompressionStatus.java @@ -18,7 +18,8 @@ package net.szum123321.textile_backup.core; -import java.io.Serializable; +import java.io.*; +import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; import java.util.Map; @@ -27,4 +28,19 @@ public record CompressionStatus(long treeHash, LocalDateTime date, long startTim public static final String DATA_FILENAME = "textile_status.data"; public boolean isValid(long decompressedHash) { return true; } + public static CompressionStatus readFromFile(Path f) throws IOException, ClassNotFoundException { + try(InputStream i = Files.newInputStream(f); + ObjectInputStream obj = new ObjectInputStream(i)) { + return (CompressionStatus) obj.readObject(); + } + } + + public byte[] serialize() throws IOException { + try (ByteArrayOutputStream bo = new ByteArrayOutputStream(); + ObjectOutputStream o = new ObjectOutputStream(bo)) { + o.writeObject(this); + return bo.toByteArray(); + } + } + } 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 63a3e3e..99e1474 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 @@ -24,11 +24,14 @@ import net.minecraft.server.command.ServerCommandSource; import net.szum123321.textile_backup.core.ActionInitiator; import org.jetbrains.annotations.NotNull; +import java.time.LocalDateTime; + public record BackupContext(@NotNull MinecraftServer server, ServerCommandSource commandSource, ActionInitiator initiator, boolean save, - String comment) { + String comment, + LocalDateTime startDate) { public boolean startedByPlayer() { return initiator == ActionInitiator.Player; @@ -103,7 +106,7 @@ public record BackupContext(@NotNull MinecraftServer server, else throw new RuntimeException("Neither MinecraftServer or ServerCommandSource were provided!"); } - return new BackupContext(server, commandSource, initiator, save, comment); + return new BackupContext(server, commandSource, initiator, save, comment, LocalDateTime.now()); } } } 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 e142173..0c79657 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 @@ -36,7 +36,6 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.time.LocalDateTime; /** * The actual object responsible for creating the backup @@ -53,7 +52,14 @@ public class MakeBackupRunnable implements Runnable { @Override public void run() { + Path outFile = Utilities + .getBackupRootPath(Utilities.getLevelName(context.server())) + .resolve(getFileName()); + + log.trace("Outfile is: {}", outFile); + try { + //I think I should synchronise those two next calls... Utilities.disableWorldSaving(context.server()); Globals.INSTANCE.disableWatchdog = true; @@ -65,12 +71,6 @@ public class MakeBackupRunnable implements Runnable { log.trace("Minecraft world is: {}", world); - Path outFile = Utilities - .getBackupRootPath(Utilities.getLevelName(context.server())) - .resolve(getFileName()); - - log.trace("Outfile is: {}", outFile); - Files.createDirectories(outFile.getParent()); Files.createFile(outFile); @@ -118,6 +118,14 @@ public class MakeBackupRunnable implements Runnable { //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().errorErrorHandlingMode.isStrict()) { + try { + Files.delete(outFile); + } catch (IOException ex) { + log.error("An exception occurred while tryin go delete: {}", outFile, ex); + } + } + if(context.initiator() == ActionInitiator.Player) log.sendError(context, "An exception occurred when trying to create new backup file!"); } finally { @@ -127,9 +135,7 @@ public class MakeBackupRunnable implements Runnable { } private String getFileName(){ - LocalDateTime now = LocalDateTime.now(); - - return Utilities.getDateTimeFormatter().format(now) + + 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/compressors/AbstractCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java index f27a358..b689ba7 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 @@ -21,7 +21,6 @@ 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.config.ConfigHelper; -import net.szum123321.textile_backup.config.ConfigPOJO; import net.szum123321.textile_backup.core.*; import net.szum123321.textile_backup.core.create.BackupContext; import net.szum123321.textile_backup.core.create.BrokenFileHandler; @@ -42,14 +41,12 @@ 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) { + public void createArchive(Path inputFile, Path outputFile, BackupContext ctx, int coreLimit) throws IOException, ExecutionException, InterruptedException { Instant start = Instant.now(); FileTreeHashBuilder fileHashBuilder = new FileTreeHashBuilder(() -> null); //TODO: select hashing algorithm BrokenFileHandler brokenFileHandler = new BrokenFileHandler(); - boolean keep = true; - try (OutputStream outStream = Files.newOutputStream(outputFile); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outStream); OutputStream arc = createArchiveOutputStream(bufferedOutputStream, ctx, coreLimit); @@ -62,39 +59,35 @@ public abstract class AbstractCompressor { Path file = it.next(); try { - addEntry(new FileInputStreamSupplier(file, inputFile.relativize(file).toString(), fileHashBuilder, brokenFileHandler), arc); - } catch (Exception e) { - if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode == ConfigPOJO.ErrorHandlingMode.STRICT) { - keep = false; - break; - } + addEntry( + new FileInputStreamSupplier( + file, + inputFile.relativize(file).toString(), + fileHashBuilder, + brokenFileHandler), + arc + ); + } catch (IOException e) { brokenFileHandler.handle(file, e); + if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode.isStrict()) throw e; + else log.sendErrorAL(ctx, "An exception occurred while trying to compress: {}", + inputFile.relativize(file).toString(), e + ); } } - //If there are still files left in the stream, we should handle them - while(it.hasNext()) { - Path file = it.next(); - brokenFileHandler.handle(file, new DataLeftException(Files.size(file))); - } - Instant now = Instant.now(); CompressionStatus status = new CompressionStatus ( fileHashBuilder.getValue(), - null, start.toEpochMilli(), now.toEpochMilli(), + ctx.startDate(), start.toEpochMilli(), now.toEpochMilli(), brokenFileHandler.get() ); - //Serialize using gson? - try (ByteArrayOutputStream bo = new ByteArrayOutputStream(); - ObjectOutputStream o = new ObjectOutputStream(bo)) { - o.writeObject(status); - addEntry(new StatusFileInputSupplier(bo.toByteArray()), arc); - } + addEntry(new StatusFileInputSupplier(status.serialize()), arc); finish(arc); - } catch(NoSpaceLeftOnDeviceException e) { + } /*catch(NoSpaceLeftOnDeviceException e) { log.error(""" CRITICAL ERROR OCCURRED! The backup is corrupt! @@ -106,14 +99,14 @@ public abstract class AbstractCompressor { log.sendError(ctx, "Backup failed. The file is corrupt."); log.error("For help see: https://github.com/Szum123321/textile_backup/wiki/ZIP-Problems"); } - if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode == ConfigPOJO.ErrorHandlingMode.STRICT) keep = false; + if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode.isStrict()) keep = false; } catch (IOException | InterruptedException | ExecutionException e) { log.error("An exception occurred!", e); if(ctx.initiator() == ActionInitiator.Player) log.sendError(ctx, "Something went wrong while compressing files!"); - if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode == ConfigPOJO.ErrorHandlingMode.STRICT) keep = false; + if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode.isStrict()) keep = false; - } finally { + } */finally { close(); } 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 7ca5f67..f41f0b8 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 @@ -96,8 +96,7 @@ public class ParallelZipCompressor extends ZipCompressor { boolean match = (cause.getStackTrace().length >= STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE.length); if(match) { for(int i = 0; i < STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE.length && match; i++) - if(!STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE[i].equals(cause.getStackTrace()[i])) match = false; - + if(!STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE[i].matches(cause.getStackTrace()[i])) match = false; //For clarity's sake let's not throw the ExecutionException itself rather only the cause, as the EE is just the wrapper if(match) throw new NoSpaceLeftOnDeviceException(cause); @@ -113,17 +112,8 @@ public class ParallelZipCompressor extends ZipCompressor { String methodName, boolean isNative ) { - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null) return false; - if(o.getClass() == StackTraceElement.class) { - StackTraceElement that = (StackTraceElement) o; - return (isNative == that.isNativeMethod()) && Objects.equals(className, that.getClassName()) && Objects.equals(methodName, that.getMethodName()); - } - if(getClass() != o.getClass()) return false; - SimpleStackTraceElement that = (SimpleStackTraceElement) o; - return isNative == that.isNative && Objects.equals(className, that.className) && Objects.equals(methodName, that.methodName); + public boolean matches(StackTraceElement o) { + return (isNative == o.isNativeMethod()) && Objects.equals(className, o.getClassName()) && Objects.equals(methodName, o.getMethodName()); } } }