Files
justbackup/src/main/java/io/ib67/sfcraft/BackupWorker.java
T
2025-10-02 12:05:00 +08:00

63 lines
2.2 KiB
Java

package io.ib67.sfcraft;
import io.ib67.sfcraft.bundler.BundleWriter;
import io.ib67.sfcraft.strategy.BackupStrategy;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import net.minecraft.server.MinecraftServer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import static io.ib67.sfcraft.Globals.BACKUP_LOCK;
@Log4j2
public record BackupWorker(
MinecraftServer server,
BackupStrategy strategy,
Path tmpDir,
BackupSubject subject,
UnaryOperator<BundleWriter.BundleWriterBuilder> config
) implements Supplier<Backup> {
@SneakyThrows
public BackupWorker {
if (Files.notExists(tmpDir)) Files.createDirectories(tmpDir);
}
@Override
@SneakyThrows
public Backup get() {
if (server == null) {
throw new IllegalStateException("MinecraftServer is not initialized yet, not doing backup");
}
server.saveAll(true, true, false);
while (!BACKUP_LOCK.compareAndSet(IOState.IDLE, IOState.BACKUP)) {
log.info("Server is saving world while performing backup! waiting...");
Thread.sleep(2000);
}
// performing backup is now true
var tmpBundle = tmpDir.resolve("backup_" + subject.name() + "_" + System.currentTimeMillis() + ".swb.zst");
try {
// tmp file path
log.info("Creating bundle {}", tmpBundle);
BundleWriter.createBundle(tmpBundle, subject.changedFiles(), config);
} catch (Exception e) {
throw e;
} finally {
// Though we won't access the state within backup progress, there are certain cases
// that this state will be changed to STORAGE_SYNC.
// Also take a look at MixinRegionBasedStorage.
while (!BACKUP_LOCK.compareAndSet(IOState.BACKUP, IOState.IDLE)) {
log.error("Expect BACKUP state but got {}", BACKUP_LOCK.get());
Thread.sleep(2000);
}
}
var result = strategy.createBackup(subject.name(), subject.root(), tmpBundle);
Files.deleteIfExists(tmpBundle);
return result;
}
}