From 4a1d885afa7217b47d6183488c3dc6537cef05b6 Mon Sep 17 00:00:00 2001 From: Keuin Date: Sat, 23 Jan 2021 14:10:32 +0800 Subject: Version 1.4.6 (preview): added metadata for incremental backup (need integrated test and display implementation) --- .../serializer/IncBackupInfoSerializer.java | 65 ++++++++++++++ .../incremental/serializer/SavedIncBackupV0.java | 64 +++++++++++++ .../incremental/serializer/SavedIncBackupV1.java | 100 +++++++++++++++++++++ .../serializer/SavedIncrementalBackup.java | 62 +++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/IncBackupInfoSerializer.java create mode 100644 src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV0.java create mode 100644 src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV1.java create mode 100644 src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncrementalBackup.java (limited to 'src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer') diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/IncBackupInfoSerializer.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/IncBackupInfoSerializer.java new file mode 100644 index 0000000..45590ba --- /dev/null +++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/IncBackupInfoSerializer.java @@ -0,0 +1,65 @@ +package com.keuin.kbackupfabric.backup.incremental.serializer; + +import com.keuin.kbackupfabric.backup.incremental.ObjectCollection2; +import com.keuin.kbackupfabric.backup.incremental.ObjectCollectionConverter; +import com.keuin.kbackupfabric.backup.name.BackupFileNameEncoder; +import com.keuin.kbackupfabric.backup.name.IncrementalBackupFileNameEncoder; +import com.keuin.kbackupfabric.util.backup.incremental.ObjectCollection; + +import java.io.*; +import java.util.Objects; + +public class IncBackupInfoSerializer { + /** + * Load incremental backup index file into object, no matter what version it is. + * + * @param file a valid incremental backup file. (with a valid file name) + * @return the object. Not null. + * @throws IOException when failed due to an I/O error. + */ + public static SavedIncrementalBackup fromFile(File file) throws IOException { + Objects.requireNonNull(file); + try (FileInputStream fileInputStream = new FileInputStream(file)) { + try (ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { + Object o = objectInputStream.readObject(); + if (o instanceof SavedIncrementalBackup) { + return (SavedIncrementalBackup) o; + } else if (o instanceof ObjectCollection) { + // backward compatibility with old-style (v0) incremental backup + BackupFileNameEncoder.BackupBasicInformation info = new IncrementalBackupFileNameEncoder().decode(file.getName()); + if (info == null) + throw new IOException("Invalid backup file name."); + return new SavedIncBackupV0(ObjectCollectionConverter.convert((ObjectCollection) o), info); + } else if (o instanceof ObjectCollection2) { + // compatible with 1.4.6 implementation + BackupFileNameEncoder.BackupBasicInformation info = new IncrementalBackupFileNameEncoder().decode(file.getName()); + if (info == null) + throw new IOException("Invalid backup file name."); + return new SavedIncBackupV0((ObjectCollection2) o, info); + } else { + throw new RuntimeException("Unrecognized backup file format: unknown class " + o.getClass().getCanonicalName()); + } + } catch (ClassNotFoundException e) { + // this should not happen + throw new RuntimeException(e); + } + } + } + + /** + * Save incremental backup index and metadata into file. + * + * @param file the file. + * @param backup the backup. + * @throws IOException when failed due to an I/O error. + */ + public static void toFile(File file, SavedIncrementalBackup backup) throws IOException { + Objects.requireNonNull(file); + Objects.requireNonNull(backup); + try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) { + objectOutputStream.writeObject(backup); + } + } + } +} diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV0.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV0.java new file mode 100644 index 0000000..8b4a4a1 --- /dev/null +++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV0.java @@ -0,0 +1,64 @@ +package com.keuin.kbackupfabric.backup.incremental.serializer; + +import com.keuin.kbackupfabric.backup.incremental.ObjectCollection2; +import com.keuin.kbackupfabric.backup.name.BackupFileNameEncoder; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * The old-style incremental backup. Just to keep backward compatibility with old backups. + */ +public class SavedIncBackupV0 implements SavedIncrementalBackup { + + private final ObjectCollection2 objectCollection2; + private final String backupName; + private final LocalDateTime namedBackupTime; + + public SavedIncBackupV0(ObjectCollection2 objectCollection2, BackupFileNameEncoder.BackupBasicInformation backupBasicInformation) { + Objects.requireNonNull(objectCollection2); + Objects.requireNonNull(backupBasicInformation); + + this.objectCollection2 = objectCollection2; + this.backupName = backupBasicInformation.customName; + this.namedBackupTime = backupBasicInformation.time; + } + + + @Override + public ObjectCollection2 getObjectCollection() { + return objectCollection2; + } + + @Override + public String getBackupName() { + return backupName; + } + + @Override + public ZonedDateTime getBackupTime() { + return namedBackupTime.atZone(ZoneId.systemDefault()); + } + + @Override + public int getFilesAdded() { + return -1; // missing info + } + + @Override + public long getTotalSizeBytes() { + return -1; // missing info + } + + @Override + public long getIncreasedSizeBytes() { + return -1; // missing info + } + + @Override + public String toString() { + return String.format("(Legacy Backup) %s, created at %s", backupName, namedBackupTime); + } +} diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV1.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV1.java new file mode 100644 index 0000000..0ebe06a --- /dev/null +++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncBackupV1.java @@ -0,0 +1,100 @@ +package com.keuin.kbackupfabric.backup.incremental.serializer; + +import com.keuin.kbackupfabric.backup.BackupFilesystemUtil; +import com.keuin.kbackupfabric.backup.incremental.ObjectCollection2; + +import java.io.Serializable; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +public class SavedIncBackupV1 implements SavedIncrementalBackup, Serializable { + + private final ObjectCollection2 objectCollection2; + private final String backupName; + private final ZonedDateTime backupTime; + private final long totalSizeBytes; + private final long increasedSizeBytes; + private final int filesAdded; + private final int totalFiles; + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"); + + public SavedIncBackupV1(ObjectCollection2 objectCollection2, String backupName, ZonedDateTime backupTime, long totalSizeBytes, long increasedSizeBytes, int filesAdded, int totalFiles) { + this.totalFiles = totalFiles; + Objects.requireNonNull(objectCollection2); + Objects.requireNonNull(backupName); + Objects.requireNonNull(backupTime); + this.objectCollection2 = objectCollection2; + this.backupName = backupName; + this.backupTime = backupTime; + this.totalSizeBytes = totalSizeBytes; + this.increasedSizeBytes = increasedSizeBytes; + this.filesAdded = filesAdded; + } + + @Override + public ObjectCollection2 getObjectCollection() { + return objectCollection2; + } + + @Override + public String getBackupName() { + return backupName; + } + + @Override + public ZonedDateTime getBackupTime() { + return backupTime; + } + + @Override + public int getFilesAdded() { + return filesAdded; + } + + @Override + public long getTotalSizeBytes() { + return totalSizeBytes; + } + + @Override + public long getIncreasedSizeBytes() { + return increasedSizeBytes; + } + + public int getTotalFiles() { + return totalFiles; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SavedIncBackupV1 that = (SavedIncBackupV1) o; + return totalSizeBytes == that.totalSizeBytes && + increasedSizeBytes == that.increasedSizeBytes && + filesAdded == that.filesAdded && + totalFiles == that.totalFiles && + objectCollection2.equals(that.objectCollection2) && + backupName.equals(that.backupName) && + backupTime.equals(that.backupTime); + } + + @Override + public int hashCode() { + return Objects.hash(objectCollection2, backupName, backupTime, totalSizeBytes, increasedSizeBytes, filesAdded, totalFiles); + } + + @Override + public String toString() { + return String.format( + "%s, created at %s, files: %d (total size: %s), copied size: %s, files added: %d", + backupName, + backupTime.format(formatter), + totalFiles, + BackupFilesystemUtil.getFriendlyFileSizeString(totalSizeBytes), + BackupFilesystemUtil.getFriendlyFileSizeString(increasedSizeBytes), + filesAdded + ); + } +} diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncrementalBackup.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncrementalBackup.java new file mode 100644 index 0000000..e2e50b6 --- /dev/null +++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/serializer/SavedIncrementalBackup.java @@ -0,0 +1,62 @@ +package com.keuin.kbackupfabric.backup.incremental.serializer; + + +import com.keuin.kbackupfabric.backup.incremental.ObjectCollection2; + +import java.io.Serializable; +import java.time.ZonedDateTime; + +/** + * The abstraction of an object saved in the disk, containing all information (except binary data of files) about an incremental backup. + */ +public interface SavedIncrementalBackup extends Serializable { + + /** + * Get an instance with the latest version. + */ + static SavedIncrementalBackup newLatest(ObjectCollection2 objectCollection2, String backupName, ZonedDateTime backupTime, long totalSizeBytes, long increasedSizeBytes, int filesAdded, int totalFiles) { + return new SavedIncBackupV1(objectCollection2, backupName, backupTime, totalSizeBytes, increasedSizeBytes, filesAdded, totalFiles); + } + + /** + * Get the object collection of the level directory. + * + * @return the object collection. + */ + ObjectCollection2 getObjectCollection(); + + /** + * Get the custom backup name. + * + * @return the backup name. + */ + String getBackupName(); + + /** + * Get the time when this backup was made. + * + * @return the time. + */ + ZonedDateTime getBackupTime(); + + /** + * Get new files added to the base. + * + * @return file count. + */ + int getFilesAdded(); + + /** + * Get the total size of the saved world. + * + * @return the size in bytes. + */ + long getTotalSizeBytes(); + + /** + * Get the size we cost to add this backup into the base. + * + * @return the increased size in bytes. + */ + long getIncreasedSizeBytes(); +} -- cgit v1.2.3