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 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(

View File

@ -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 {

View File

@ -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();
}
}
}

View File

@ -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());
}
}
}

View File

@ -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();
}

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.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();
}

View File

@ -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());
}
}
}