Merged BackuContext, MakeBackupRunnable, MakeBackupRunnableFactory into ExecutableBackup
parent
27d6d68e97
commit
6782c4fe5f
|
@ -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.digest.Hash;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
import net.szum123321.textile_backup.core.Utilities;
|
||||||
|
|
||||||
import net.szum123321.textile_backup.core.create.MakeBackupRunnable;
|
|
||||||
import net.szum123321.textile_backup.core.restore.AwaitThread;
|
import net.szum123321.textile_backup.core.restore.AwaitThread;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
|
@ -70,8 +69,8 @@ public class Globals {
|
||||||
if(!executorService.awaitTermination(timeout, TimeUnit.MICROSECONDS)) {
|
if(!executorService.awaitTermination(timeout, TimeUnit.MICROSECONDS)) {
|
||||||
log.error("Timeout occurred while waiting for currently running backups to finish!");
|
log.error("Timeout occurred while waiting for currently running backups to finish!");
|
||||||
executorService.shutdownNow().stream()
|
executorService.shutdownNow().stream()
|
||||||
.filter(r -> r instanceof MakeBackupRunnable)
|
// .filter(r -> r instanceof ExecutableBackup)
|
||||||
.map(r -> (MakeBackupRunnable)r)
|
// .map(r -> (ExecutableBackup)r)
|
||||||
.forEach(r -> log.error("Dropping: {}", r.toString()));
|
.forEach(r -> log.error("Dropping: {}", r.toString()));
|
||||||
if(!executorService.awaitTermination(1000, TimeUnit.MICROSECONDS))
|
if(!executorService.awaitTermination(1000, TimeUnit.MICROSECONDS))
|
||||||
log.error("Couldn't shut down the executor!");
|
log.error("Couldn't shut down the executor!");
|
||||||
|
|
|
@ -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.ConfigHelper;
|
||||||
import net.szum123321.textile_backup.config.ConfigPOJO;
|
import net.szum123321.textile_backup.config.ConfigPOJO;
|
||||||
import net.szum123321.textile_backup.core.ActionInitiator;
|
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.BackupScheduler;
|
||||||
import net.szum123321.textile_backup.core.create.MakeBackupRunnableFactory;
|
import net.szum123321.textile_backup.core.create.ExecutableBackup;
|
||||||
import net.szum123321.textile_backup.test.BalticHashTest;
|
import net.szum123321.textile_backup.test.BalticHashTest;
|
||||||
|
|
||||||
public class TextileBackup implements ModInitializer {
|
public class TextileBackup implements ModInitializer {
|
||||||
|
@ -82,14 +81,14 @@ public class TextileBackup implements ModInitializer {
|
||||||
|
|
||||||
if (config.get().shutdownBackup && Globals.INSTANCE.globalShutdownBackupFlag.get()) {
|
if (config.get().shutdownBackup && Globals.INSTANCE.globalShutdownBackupFlag.get()) {
|
||||||
try {
|
try {
|
||||||
MakeBackupRunnableFactory.create(
|
ExecutableBackup.Builder
|
||||||
BackupContext.Builder
|
|
||||||
.newBackupContextBuilder()
|
.newBackupContextBuilder()
|
||||||
.setServer(server)
|
.setServer(server)
|
||||||
.setInitiator(ActionInitiator.Shutdown)
|
.setInitiator(ActionInitiator.Shutdown)
|
||||||
.setComment("shutdown")
|
.setComment("shutdown")
|
||||||
|
.announce()
|
||||||
.build()
|
.build()
|
||||||
).call();
|
.call();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,7 +23,7 @@ import net.minecraft.text.Text;
|
||||||
import net.minecraft.text.MutableText;
|
import net.minecraft.text.MutableText;
|
||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
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.Level;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
@ -112,7 +112,7 @@ public class TextileLogger {
|
||||||
sendFeedback(Level.INFO, source, msg, args);
|
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);
|
sendInfo(context.commandSource(), msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,8 @@ public class TextileLogger {
|
||||||
sendFeedback(Level.ERROR, source, msg, args);
|
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);
|
sendError(context.commandSource(), msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@ public class TextileLogger {
|
||||||
sendToPlayerAndLog(Level.INFO, source, msg, args);
|
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);
|
sendInfoAL(context.commandSource(), msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +143,7 @@ public class TextileLogger {
|
||||||
sendToPlayerAndLog(Level.ERROR, source, msg, args);
|
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);
|
sendErrorAL(context.commandSource(), msg, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,7 @@ import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.szum123321.textile_backup.Globals;
|
import net.szum123321.textile_backup.Globals;
|
||||||
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.core.create.BackupContext;
|
import net.szum123321.textile_backup.core.create.ExecutableBackup;
|
||||||
import net.szum123321.textile_backup.core.create.MakeBackupRunnableFactory;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -42,15 +41,13 @@ public class StartBackupCommand {
|
||||||
|
|
||||||
private static int execute(ServerCommandSource source, @Nullable String comment) {
|
private static int execute(ServerCommandSource source, @Nullable String comment) {
|
||||||
Globals.INSTANCE.getQueueExecutor().submit(
|
Globals.INSTANCE.getQueueExecutor().submit(
|
||||||
MakeBackupRunnableFactory.create(
|
ExecutableBackup.Builder
|
||||||
BackupContext.Builder
|
|
||||||
.newBackupContextBuilder()
|
.newBackupContextBuilder()
|
||||||
.setCommandSource(source)
|
.setCommandSource(source)
|
||||||
.setComment(comment)
|
.setComment(comment)
|
||||||
.guessInitiator()
|
.guessInitiator()
|
||||||
.saveServer()
|
.saveServer()
|
||||||
.build()
|
.build()
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -53,14 +53,13 @@ public class BackupScheduler {
|
||||||
if(nextBackup <= now) {
|
if(nextBackup <= now) {
|
||||||
//It's time to run
|
//It's time to run
|
||||||
Globals.INSTANCE.getQueueExecutor().submit(
|
Globals.INSTANCE.getQueueExecutor().submit(
|
||||||
MakeBackupRunnableFactory.create(
|
ExecutableBackup.Builder
|
||||||
BackupContext.Builder
|
|
||||||
.newBackupContextBuilder()
|
.newBackupContextBuilder()
|
||||||
.setServer(server)
|
.setServer(server)
|
||||||
.setInitiator(ActionInitiator.Timer)
|
.setInitiator(ActionInitiator.Timer)
|
||||||
.saveServer()
|
.saveServer()
|
||||||
|
.announce()
|
||||||
.build()
|
.build()
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
nextBackup = now + config.get().backupInterval;
|
nextBackup = now + config.get().backupInterval;
|
||||||
|
@ -76,14 +75,13 @@ public class BackupScheduler {
|
||||||
if(scheduled && nextBackup <= now) {
|
if(scheduled && nextBackup <= now) {
|
||||||
//Verify we hadn't done the final one, and it's time to do so
|
//Verify we hadn't done the final one, and it's time to do so
|
||||||
Globals.INSTANCE.getQueueExecutor().submit(
|
Globals.INSTANCE.getQueueExecutor().submit(
|
||||||
MakeBackupRunnableFactory.create(
|
ExecutableBackup.Builder
|
||||||
BackupContext.Builder
|
|
||||||
.newBackupContextBuilder()
|
.newBackupContextBuilder()
|
||||||
.setServer(server)
|
.setServer(server)
|
||||||
.setInitiator(ActionInitiator.Timer)
|
.setInitiator(ActionInitiator.Timer)
|
||||||
.saveServer()
|
.saveServer()
|
||||||
|
.announce()
|
||||||
.build()
|
.build()
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
scheduled = false;
|
scheduled = false;
|
||||||
|
|
|
@ -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<Void> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<Void> {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<Void> 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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,8 +23,8 @@ 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.core.*;
|
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.BrokenFileHandler;
|
||||||
|
import net.szum123321.textile_backup.core.create.ExecutableBackup;
|
||||||
import net.szum123321.textile_backup.core.create.FileInputStreamSupplier;
|
import net.szum123321.textile_backup.core.create.FileInputStreamSupplier;
|
||||||
import net.szum123321.textile_backup.core.create.InputSupplier;
|
import net.szum123321.textile_backup.core.create.InputSupplier;
|
||||||
import net.szum123321.textile_backup.core.digest.FileTreeHashBuilder;
|
import net.szum123321.textile_backup.core.digest.FileTreeHashBuilder;
|
||||||
|
@ -44,7 +44,7 @@ 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) throws IOException, ExecutionException, InterruptedException {
|
public void createArchive(Path inputFile, Path outputFile, ExecutableBackup ctx, int coreLimit) throws IOException, ExecutionException, InterruptedException {
|
||||||
Instant start = Instant.now();
|
Instant start = Instant.now();
|
||||||
|
|
||||||
BrokenFileHandler brokenFileHandler = new BrokenFileHandler(); //Basically a hashmap storing files and their respective exceptions
|
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())));
|
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 abstract void addEntry(InputSupplier inputSupplier, OutputStream arc) throws IOException;
|
||||||
|
|
||||||
protected void finish(OutputStream arc) throws InterruptedException, ExecutionException, IOException {
|
protected void finish(OutputStream arc) throws InterruptedException, ExecutionException, IOException {
|
||||||
|
|
|
@ -21,7 +21,7 @@ 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.core.NoSpaceLeftOnDeviceException;
|
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 net.szum123321.textile_backup.core.create.InputSupplier;
|
||||||
import org.apache.commons.compress.archivers.zip.*;
|
import org.apache.commons.compress.archivers.zip.*;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public class ParallelZipCompressor extends ZipCompressor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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));
|
scatterZipCreator = new ParallelScatterZipCreator(Executors.newFixedThreadPool(coreLimit));
|
||||||
return super.createArchiveOutputStream(stream, ctx, coreLimit);
|
return super.createArchiveOutputStream(stream, ctx, coreLimit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ package net.szum123321.textile_backup.core.create.compressors;
|
||||||
|
|
||||||
import net.szum123321.textile_backup.config.ConfigHelper;
|
import net.szum123321.textile_backup.config.ConfigHelper;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
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 net.szum123321.textile_backup.core.create.InputSupplier;
|
||||||
import org.apache.commons.compress.archivers.zip.Zip64Mode;
|
import org.apache.commons.compress.archivers.zip.Zip64Mode;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
|
@ -43,7 +43,7 @@ public class ZipCompressor extends AbstractCompressor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OutputStream createArchiveOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) {
|
protected OutputStream createArchiveOutputStream(OutputStream stream, ExecutableBackup ctx, int coreLimit) {
|
||||||
ZipArchiveOutputStream arc = new ZipArchiveOutputStream(stream);
|
ZipArchiveOutputStream arc = new ZipArchiveOutputStream(stream);
|
||||||
|
|
||||||
arc.setMethod(ZipArchiveOutputStream.DEFLATED);
|
arc.setMethod(ZipArchiveOutputStream.DEFLATED);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package net.szum123321.textile_backup.core.create.compressors.tar;
|
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.compressors.AbstractCompressor;
|
||||||
import net.szum123321.textile_backup.core.create.InputSupplier;
|
import net.szum123321.textile_backup.core.create.InputSupplier;
|
||||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
||||||
|
@ -28,12 +28,12 @@ import org.apache.commons.compress.utils.IOUtils;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
public class AbstractTarArchiver extends AbstractCompressor {
|
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;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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));
|
TarArchiveOutputStream tar = new TarArchiveOutputStream(getCompressorOutputStream(stream, ctx, coreLimit));
|
||||||
tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
|
tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
|
||||||
tar.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
|
tar.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package net.szum123321.textile_backup.core.create.compressors.tar;
|
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.BZip2OutputStream;
|
||||||
import org.at4j.comp.bzip2.BZip2OutputStreamSettings;
|
import org.at4j.comp.bzip2.BZip2OutputStreamSettings;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public class ParallelBZip2Compressor extends AbstractTarArchiver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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));
|
return new BZip2OutputStream(stream, new BZip2OutputStreamSettings().setNumberOfEncoderThreads(coreLimit));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package net.szum123321.textile_backup.core.create.compressors.tar;
|
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 org.anarres.parallelgzip.ParallelGZIPOutputStream;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -33,7 +33,7 @@ public class ParallelGzipCompressor extends AbstractTarArchiver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
executorService = Executors.newFixedThreadPool(coreLimit);
|
||||||
|
|
||||||
return new ParallelGZIPOutputStream(stream, executorService);
|
return new ParallelGZIPOutputStream(stream, executorService);
|
||||||
|
|
|
@ -26,8 +26,7 @@ import net.szum123321.textile_backup.config.ConfigPOJO;
|
||||||
import net.szum123321.textile_backup.core.ActionInitiator;
|
import net.szum123321.textile_backup.core.ActionInitiator;
|
||||||
import net.szum123321.textile_backup.core.CompressionStatus;
|
import net.szum123321.textile_backup.core.CompressionStatus;
|
||||||
import net.szum123321.textile_backup.core.Utilities;
|
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.MakeBackupRunnableFactory;
|
|
||||||
import net.szum123321.textile_backup.core.restore.decompressors.GenericTarDecompressor;
|
import net.szum123321.textile_backup.core.restore.decompressors.GenericTarDecompressor;
|
||||||
import net.szum123321.textile_backup.core.restore.decompressors.ZipDecompressor;
|
import net.szum123321.textile_backup.core.restore.decompressors.ZipDecompressor;
|
||||||
import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor;
|
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
|
ctx.server().getThread().join(); //wait for server thread to die and save all its state
|
||||||
|
|
||||||
if(config.get().backupOldWorlds) {
|
if(config.get().backupOldWorlds) {
|
||||||
return MakeBackupRunnableFactory.create (
|
return ExecutableBackup.Builder
|
||||||
BackupContext.Builder
|
|
||||||
.newBackupContextBuilder()
|
.newBackupContextBuilder()
|
||||||
.setServer(ctx.server())
|
.setServer(ctx.server())
|
||||||
.setInitiator(ActionInitiator.Restore)
|
.setInitiator(ActionInitiator.Restore)
|
||||||
.dontCleanup()
|
.noCleanup()
|
||||||
.setComment("Old_World" + (ctx.comment() != null ? "_" + ctx.comment() : ""))
|
.setComment("Old_World" + (ctx.comment() != null ? "_" + ctx.comment() : ""))
|
||||||
.build()
|
.announce()
|
||||||
).call();
|
.build().call();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//run the thread.
|
||||||
new Thread(waitForShutdown, "Server shutdown wait thread").start();
|
new Thread(waitForShutdown, "Server shutdown wait thread").start();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -106,7 +104,7 @@ public class RestoreBackupRunnable implements Runnable {
|
||||||
|
|
||||||
log.info("Waiting for server to fully terminate...");
|
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();
|
waitForShutdown.get();
|
||||||
|
|
||||||
Optional<String> errorMsg;
|
Optional<String> errorMsg;
|
||||||
|
@ -127,8 +125,8 @@ public class RestoreBackupRunnable implements Runnable {
|
||||||
if (errorMsg.isEmpty()) log.info("Backup valid. Restoring");
|
if (errorMsg.isEmpty()) log.info("Backup valid. Restoring");
|
||||||
else log.info("Backup is damaged, but verification is disabled [{}]. Restoring", errorMsg.get());
|
else log.info("Backup is damaged, but verification is disabled [{}]. Restoring", errorMsg.get());
|
||||||
|
|
||||||
((MinecraftServerSessionAccessor) ctx.server())
|
//Disables write lock to override world file
|
||||||
.getSession().close();
|
((MinecraftServerSessionAccessor) ctx.server()).getSession().close();
|
||||||
|
|
||||||
Utilities.deleteDirectory(worldFile);
|
Utilities.deleteDirectory(worldFile);
|
||||||
Files.move(tmp, worldFile);
|
Files.move(tmp, worldFile);
|
||||||
|
|
Loading…
Reference in New Issue