From 7444c2b1f281b5b147717ba2a2ed6798c66a057b Mon Sep 17 00:00:00 2001 From: Keuin Date: Mon, 27 Apr 2020 17:42:07 +0800 Subject: Resized the logo to reduce plugin size. Refactored code for a better implementation of async and blocking task. --- .../kbackupfabric/operation/RestoreOperation.java | 92 ++++++++++++++++++++-- 1 file changed, 84 insertions(+), 8 deletions(-) (limited to 'src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java') diff --git a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java index 4b129d9..cc19627 100644 --- a/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java +++ b/src/main/java/com/keuin/kbackupfabric/operation/RestoreOperation.java @@ -1,37 +1,49 @@ package com.keuin.kbackupfabric.operation; +import com.keuin.kbackupfabric.operation.abstracts.InvokableBlockingOperation; import com.keuin.kbackupfabric.util.PrintUtil; -import com.keuin.kbackupfabric.worker.RestoreWorker; +import com.keuin.kbackupfabric.util.ZipUtil; +import com.keuin.kbackupfabric.util.ZipUtilException; import com.mojang.brigadier.context.CommandContext; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import java.io.File; +import java.io.IOException; -import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.*; +import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.getBackupFileName; +import static com.keuin.kbackupfabric.util.BackupFilesystemUtil.getBackupSaveDirectory; +import static org.apache.commons.io.FileUtils.forceDelete; -class RestoreOperation extends AbstractConfirmableOperation { +public class RestoreOperation extends InvokableBlockingOperation { //private static final Logger LOGGER = LogManager.getLogger(); private final String backupName; + private final Thread serverThread; + private final String backupFilePath; + private final String levelDirectory; private final CommandContext context; + private final MinecraftServer server; - RestoreOperation(CommandContext context, String backupName) { + public RestoreOperation(CommandContext context, String backupFilePath, String levelDirectory, String backupName) { + server = context.getSource().getMinecraftServer(); this.backupName = backupName; + this.serverThread = server.getThread(); + this.backupFilePath = backupFilePath; + this.levelDirectory = levelDirectory; this.context = context; } @Override - public boolean confirm() { + protected boolean blockingContext() { // do restore to backupName - MinecraftServer server = context.getSource().getMinecraftServer(); PrintUtil.broadcast(String.format("Restoring to previous world %s ...", backupName)); String backupFileName = getBackupFileName(backupName); PrintUtil.debug("Backup file name: " + backupFileName); File backupFile = new File(getBackupSaveDirectory(server), backupFileName); - PrintUtil.msgInfo(context, "Server will shutdown in a few seconds, depended on your world size and the disk speed, the restore progress may take seconds or minutes.", true); + PrintUtil.msgInfo(context, "Server will shutdown in a few seconds, depending on world size and disk speed, the progress may take from seconds to minutes.", true); PrintUtil.msgInfo(context, "Please do not force the server stop, or the level would be broken.", true); PrintUtil.msgInfo(context, "After it shuts down, please restart the server manually.", true); final int WAIT_SECONDS = 10; @@ -42,7 +54,14 @@ class RestoreOperation extends AbstractConfirmableOperation { } } PrintUtil.broadcast("Shutting down ..."); - RestoreWorker.invoke(server, backupFile.getPath(), getLevelPath(server)); + //RestoreWorker worker = new RestoreWorker(server.getThread(), backupFilePath, levelDirectory); + Thread workerThread = new Thread(new WorkerThread(), "RestoreWorker"); + workerThread.start(); + try { + Thread.sleep(500); + } catch (InterruptedException ignored) { + } + server.stop(false); return true; } @@ -50,4 +69,61 @@ class RestoreOperation extends AbstractConfirmableOperation { public String toString() { return String.format("restoration from %s", backupName); } + + private class WorkerThread implements Runnable { + + @Override + public void run() { + try { + // Wait server thread die + PrintUtil.info("Waiting for the server thread to exit ..."); + while (serverThread.isAlive()) { + try { + serverThread.join(); + } catch (InterruptedException ignored) { + } + } + + PrintUtil.info("Wait for 5 seconds ..."); + try { + Thread.sleep(5000); + } catch (InterruptedException ignored) { + } + + // Delete old level + PrintUtil.info("Server stopped. Deleting old level ..."); + File levelDirFile = new File(levelDirectory); + long startTime = System.currentTimeMillis(); + + int failedCounter = 0; + final int MAX_RETRY_TIMES = 20; + while (failedCounter < MAX_RETRY_TIMES) { + System.gc(); + if (!levelDirFile.delete() && levelDirFile.exists()) { + System.gc(); + forceDelete(levelDirFile); // Try to force delete. + } + if (!levelDirFile.exists()) + break; + ++failedCounter; + try { + Thread.sleep(500); + } catch (InterruptedException ignored) { + } + } + if (levelDirFile.exists()) { + PrintUtil.error(String.format("Cannot restore: failed to delete old level %s .", levelDirFile.getName())); + return; + } + + // Decompress archive + PrintUtil.info("Decompressing archived level ..."); + ZipUtil.unzip(backupFilePath, levelDirectory, false); + long endTime = System.currentTimeMillis(); + PrintUtil.info(String.format("Restore complete! (%.2fs) Please restart the server manually.", (endTime - startTime) / 1000.0)); + } catch (SecurityException | IOException | ZipUtilException e) { + PrintUtil.error("An exception occurred while restoring: " + e.getMessage()); + } + } + } } -- cgit v1.2.3