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:
parent
4007d8f86d
commit
dbb9a71749
@ -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(
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user