Moved around error handling. LocalDateTime is now passed with BackupContext. Replaced equals method with matches in ParallelZipCompressor.SimpleStackTraceElement to avert warning.

This commit is contained in:
Szum123321 2022-11-25 09:54:44 +01:00
parent 4007d8f86d
commit dbb9a71749
7 changed files with 66 additions and 56 deletions

View File

@ -84,8 +84,8 @@ public class Globals {
public Optional<Path> getLockedFile() { return Optional.ofNullable(lockedPath); } public Optional<Path> getLockedFile() { return Optional.ofNullable(lockedPath); }
public void setLockedFile(Path p) { lockedPath = p; } public void setLockedFile(Path p) { lockedPath = p; }
public boolean disableTMPFS() { return disableTMPFiles; } public synchronized boolean disableTMPFS() { return disableTMPFiles; }
public void updateTMPFSFlag(MinecraftServer server) { public synchronized void updateTMPFSFlag(MinecraftServer server) {
disableTMPFiles = false; disableTMPFiles = false;
Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir")); Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir"));
if( if(

View File

@ -188,7 +188,9 @@ public class ConfigPOJO implements ConfigData {
public enum ErrorHandlingMode { public enum ErrorHandlingMode {
STRICT, STRICT,
PERMISSIBLE, PERMISSIBLE,
VERY_PERMISSIBLE VERY_PERMISSIBLE;
public boolean isStrict() { return this == STRICT; }
} }
public enum ArchiveFormat { public enum ArchiveFormat {

View File

@ -18,7 +18,8 @@
package net.szum123321.textile_backup.core; 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.nio.file.Path;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map; 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 static final String DATA_FILENAME = "textile_status.data";
public boolean isValid(long decompressedHash) { return true; } 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();
}
}
} }

View File

@ -24,11 +24,14 @@ import net.minecraft.server.command.ServerCommandSource;
import net.szum123321.textile_backup.core.ActionInitiator; import net.szum123321.textile_backup.core.ActionInitiator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.time.LocalDateTime;
public record BackupContext(@NotNull MinecraftServer server, public record BackupContext(@NotNull MinecraftServer server,
ServerCommandSource commandSource, ServerCommandSource commandSource,
ActionInitiator initiator, ActionInitiator initiator,
boolean save, boolean save,
String comment) { String comment,
LocalDateTime startDate) {
public boolean startedByPlayer() { public boolean startedByPlayer() {
return initiator == ActionInitiator.Player; return initiator == ActionInitiator.Player;
@ -103,7 +106,7 @@ public record BackupContext(@NotNull MinecraftServer server,
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); return new BackupContext(server, commandSource, initiator, save, comment, LocalDateTime.now());
} }
} }
} }

View File

@ -36,7 +36,6 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.LocalDateTime;
/** /**
* The actual object responsible for creating the backup * The actual object responsible for creating the backup
@ -53,7 +52,14 @@ public class MakeBackupRunnable implements Runnable {
@Override @Override
public void run() { public void run() {
Path outFile = Utilities
.getBackupRootPath(Utilities.getLevelName(context.server()))
.resolve(getFileName());
log.trace("Outfile is: {}", outFile);
try { try {
//I think I should synchronise those two next calls...
Utilities.disableWorldSaving(context.server()); Utilities.disableWorldSaving(context.server());
Globals.INSTANCE.disableWatchdog = true; Globals.INSTANCE.disableWatchdog = true;
@ -65,12 +71,6 @@ public class MakeBackupRunnable implements Runnable {
log.trace("Minecraft world is: {}", world); 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.createDirectories(outFile.getParent());
Files.createFile(outFile); Files.createFile(outFile);
@ -118,6 +118,14 @@ public class MakeBackupRunnable implements Runnable {
//ExecutorService swallows exception, so I need to catch everything //ExecutorService swallows exception, so I need to catch everything
log.error("An exception occurred when trying to create new backup file!", e); 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) if(context.initiator() == ActionInitiator.Player)
log.sendError(context, "An exception occurred when trying to create new backup file!"); log.sendError(context, "An exception occurred when trying to create new backup file!");
} finally { } finally {
@ -127,9 +135,7 @@ public class MakeBackupRunnable implements Runnable {
} }
private String getFileName(){ private String getFileName(){
LocalDateTime now = LocalDateTime.now(); return Utilities.getDateTimeFormatter().format(context.startDate()) +
return Utilities.getDateTimeFormatter().format(now) +
(context.comment() != null ? "#" + context.comment().replaceAll("[\\\\/:*?\"<>|#]", "") : "") + (context.comment() != null ? "#" + context.comment().replaceAll("[\\\\/:*?\"<>|#]", "") : "") +
config.get().format.getCompleteString(); config.get().format.getCompleteString();
} }

View File

@ -21,7 +21,6 @@ package net.szum123321.textile_backup.core.create.compressors;
import net.szum123321.textile_backup.TextileBackup; import net.szum123321.textile_backup.TextileBackup;
import net.szum123321.textile_backup.TextileLogger; import net.szum123321.textile_backup.TextileLogger;
import net.szum123321.textile_backup.config.ConfigHelper; 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.*;
import net.szum123321.textile_backup.core.create.BackupContext; import net.szum123321.textile_backup.core.create.BackupContext;
import net.szum123321.textile_backup.core.create.BrokenFileHandler; import net.szum123321.textile_backup.core.create.BrokenFileHandler;
@ -42,14 +41,12 @@ import java.util.stream.Stream;
public abstract class AbstractCompressor { public abstract class AbstractCompressor {
private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); 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(); Instant start = Instant.now();
FileTreeHashBuilder fileHashBuilder = new FileTreeHashBuilder(() -> null); //TODO: select hashing algorithm FileTreeHashBuilder fileHashBuilder = new FileTreeHashBuilder(() -> null); //TODO: select hashing algorithm
BrokenFileHandler brokenFileHandler = new BrokenFileHandler(); BrokenFileHandler brokenFileHandler = new BrokenFileHandler();
boolean keep = true;
try (OutputStream outStream = Files.newOutputStream(outputFile); try (OutputStream outStream = Files.newOutputStream(outputFile);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outStream);
OutputStream arc = createArchiveOutputStream(bufferedOutputStream, ctx, coreLimit); OutputStream arc = createArchiveOutputStream(bufferedOutputStream, ctx, coreLimit);
@ -62,39 +59,35 @@ public abstract class AbstractCompressor {
Path file = it.next(); Path file = it.next();
try { try {
addEntry(new FileInputStreamSupplier(file, inputFile.relativize(file).toString(), fileHashBuilder, brokenFileHandler), arc); addEntry(
} catch (Exception e) { new FileInputStreamSupplier(
if(ConfigHelper.INSTANCE.get().errorErrorHandlingMode == ConfigPOJO.ErrorHandlingMode.STRICT) { file,
keep = false; inputFile.relativize(file).toString(),
break; fileHashBuilder,
} brokenFileHandler),
arc
);
} catch (IOException e) {
brokenFileHandler.handle(file, 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(); Instant now = Instant.now();
CompressionStatus status = new CompressionStatus ( CompressionStatus status = new CompressionStatus (
fileHashBuilder.getValue(), fileHashBuilder.getValue(),
null, start.toEpochMilli(), now.toEpochMilli(), ctx.startDate(), start.toEpochMilli(), now.toEpochMilli(),
brokenFileHandler.get() brokenFileHandler.get()
); );
//Serialize using gson? addEntry(new StatusFileInputSupplier(status.serialize()), arc);
try (ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(bo)) {
o.writeObject(status);
addEntry(new StatusFileInputSupplier(bo.toByteArray()), arc);
}
finish(arc); finish(arc);
} catch(NoSpaceLeftOnDeviceException e) { } /*catch(NoSpaceLeftOnDeviceException e) {
log.error(""" log.error("""
CRITICAL ERROR OCCURRED! CRITICAL ERROR OCCURRED!
The backup is corrupt! The backup is corrupt!
@ -106,14 +99,14 @@ public abstract class AbstractCompressor {
log.sendError(ctx, "Backup failed. The file is corrupt."); log.sendError(ctx, "Backup failed. The file is corrupt.");
log.error("For help see: https://github.com/Szum123321/textile_backup/wiki/ZIP-Problems"); 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) { } catch (IOException | InterruptedException | ExecutionException e) {
log.error("An exception occurred!", e); log.error("An exception occurred!", e);
if(ctx.initiator() == ActionInitiator.Player) if(ctx.initiator() == ActionInitiator.Player)
log.sendError(ctx, "Something went wrong while compressing files!"); 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(); close();
} }

View File

@ -96,8 +96,7 @@ public class ParallelZipCompressor extends ZipCompressor {
boolean match = (cause.getStackTrace().length >= STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE.length); boolean match = (cause.getStackTrace().length >= STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE.length);
if(match) { if(match) {
for(int i = 0; i < STACKTRACE_NO_SPACE_ON_LEFT_ON_DEVICE.length && match; i++) 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 //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); if(match) throw new NoSpaceLeftOnDeviceException(cause);
@ -113,17 +112,8 @@ public class ParallelZipCompressor extends ZipCompressor {
String methodName, String methodName,
boolean isNative boolean isNative
) { ) {
@Override public boolean matches(StackTraceElement o) {
public boolean equals(Object o) { return (isNative == o.isNativeMethod()) && Objects.equals(className, o.getClassName()) && Objects.equals(methodName, o.getMethodName());
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);
} }
} }
} }