summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/kbackupfabric/backup/incremental
diff options
context:
space:
mode:
authorKeuin <[email protected]>2021-01-24 21:15:24 +0800
committerkeuin <[email protected]>2021-01-25 02:12:49 +0800
commit1df50093bd76315905a9aae880470e81b5e1d8f0 (patch)
treef94b4d2847c2da2c820e708b6664c3246992e581 /src/main/java/com/keuin/kbackupfabric/backup/incremental
parent3648d0ca94c9954fa7c4797ce64a0f42a4f837b5 (diff)
If incremental backup failed, unfinished copy will be fully reverted.
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric/backup/incremental')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionIterator.java50
-rw-r--r--src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionSerializer.java41
-rw-r--r--src/main/java/com/keuin/kbackupfabric/backup/incremental/manager/IncrementalBackupStorageManager.java81
3 files changed, 127 insertions, 45 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionIterator.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionIterator.java
new file mode 100644
index 0000000..248d36d
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionIterator.java
@@ -0,0 +1,50 @@
+package com.keuin.kbackupfabric.backup.incremental;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+public class ObjectCollectionIterator implements Iterator<ObjectElement> {
+
+ // TODO: test this
+
+ private Iterator<ObjectElement> currentIterator;
+ private final List<ObjectCollection2> cols = new LinkedList<>();
+
+ public ObjectCollectionIterator(ObjectCollection2 collection) {
+ cols.addAll(collection.getSubCollectionSet());
+ currentIterator = collection.getElementSet().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (currentIterator != null) {
+ if (currentIterator.hasNext())
+ return true;
+ else {
+ currentIterator = null;
+ return hasNext();
+ }
+ } else {
+ if (cols.isEmpty())
+ return false;
+ else {
+ ObjectCollection2 consumedCollection = cols.remove(0);
+ cols.addAll(consumedCollection.getSubCollectionSet());
+ currentIterator = consumedCollection.getElementSet().iterator();
+ return hasNext();
+ }
+ }
+ }
+
+ @Override
+ public ObjectElement next() {
+ if (hasNext()) {
+ return currentIterator.next();
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionSerializer.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionSerializer.java
index f663f20..fa411a0 100644
--- a/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionSerializer.java
+++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/ObjectCollectionSerializer.java
@@ -1,6 +1,11 @@
package com.keuin.kbackupfabric.backup.incremental;
+import org.jetbrains.annotations.NotNull;
+
import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Iterator;
import java.util.Objects;
/**
@@ -39,4 +44,40 @@ public class ObjectCollectionSerializer {
}
}
}
+
+ public static Iterable<ObjectCollection2> fromDirectory(File directory) throws IOException {
+
+ if (!directory.isDirectory()) {
+ throw new IllegalArgumentException("Given directory is invalid.");
+ }
+ return new Iterable<ObjectCollection2>() {
+ private final Iterator<ObjectCollection2> iter = new Iterator<ObjectCollection2>() {
+ private final Iterator<Path> i = Files.walk(directory.toPath(), 1).filter(p -> {
+ File f = p.toFile();
+ return f.isFile() && f.getName().endsWith(".kbi");
+ }).iterator();
+
+ @Override
+ public boolean hasNext() {
+ return i.hasNext();
+ }
+
+ @Override
+ public ObjectCollection2 next() {
+ try {
+ return fromFile(i.next().toFile());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ @NotNull
+ @Override
+ public Iterator<ObjectCollection2> iterator() {
+ return iter;
+ }
+ };
+
+ }
}
diff --git a/src/main/java/com/keuin/kbackupfabric/backup/incremental/manager/IncrementalBackupStorageManager.java b/src/main/java/com/keuin/kbackupfabric/backup/incremental/manager/IncrementalBackupStorageManager.java
index be01966..ad7287f 100644
--- a/src/main/java/com/keuin/kbackupfabric/backup/incremental/manager/IncrementalBackupStorageManager.java
+++ b/src/main/java/com/keuin/kbackupfabric/backup/incremental/manager/IncrementalBackupStorageManager.java
@@ -1,9 +1,9 @@
package com.keuin.kbackupfabric.backup.incremental.manager;
import com.keuin.kbackupfabric.backup.incremental.ObjectCollection2;
+import com.keuin.kbackupfabric.backup.incremental.ObjectCollectionIterator;
import com.keuin.kbackupfabric.backup.incremental.ObjectElement;
import com.keuin.kbackupfabric.backup.incremental.identifier.ObjectIdentifier;
-import com.keuin.kbackupfabric.backup.incremental.identifier.StorageObjectLoader;
import com.keuin.kbackupfabric.util.FilesystemUtil;
import com.keuin.kbackupfabric.util.PrintUtil;
import org.jetbrains.annotations.Nullable;
@@ -14,6 +14,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
+import java.util.logging.Logger;
import static org.apache.commons.io.FileUtils.forceDelete;
@@ -23,6 +24,8 @@ public class IncrementalBackupStorageManager {
private final Map<ObjectIdentifier, File> map = new HashMap<>();
private boolean loaded = false;
+ private final Logger LOGGER = Logger.getLogger(IncrementalBackupStorageManager.class.getName());
+
public IncrementalBackupStorageManager(Path backupStorageBase) {
this.backupStorageBase = backupStorageBase;
}
@@ -32,7 +35,7 @@ public class IncrementalBackupStorageManager {
*
* @param collection the collection.
* @return objects copied to the base.
- * @throws IOException I/O Error.
+ * @throws IOException I/O error.
*/
public @Nullable
IncCopyResult addObjectCollection(ObjectCollection2 collection, File collectionBasePath) throws IOException {
@@ -71,6 +74,37 @@ public class IncrementalBackupStorageManager {
}
/**
+ * Delete all files in the specific collection, from the storage base.
+ *
+ * @param collection the collection containing files to be deleted.
+ * @param collectionBasePath the collection base path.
+ * @throws IOException I/O error.
+ */
+ public void deleteObjectCollection(ObjectCollection2 collection, File collectionBasePath) throws IOException {
+ deleteObjectCollection(collection, collectionBasePath, Collections.emptySet());
+ }
+
+ /**
+ * Delete a collection from the storage base, optionally preserving files used by other backups.
+ *
+ * @param collection the collection containing files to be deleted.
+ * @param collectionBasePath the collection base path.
+ * @param otherExistingCollections other collections (not to be deleted) in this base. Files exist in these collections will not be deleted.
+ */
+ public void deleteObjectCollection(ObjectCollection2 collection, File collectionBasePath,
+ Iterable<ObjectCollection2> otherExistingCollections) {
+ Iterator<ObjectElement> iter = new ObjectCollectionIterator(collection);
+ Set<ObjectElement> unusedElementSet = new HashSet<>();
+ iter.forEachRemaining(unusedElementSet::add);
+ otherExistingCollections.forEach(col -> new ObjectCollectionIterator(col).forEachRemaining(unusedElementSet::remove));
+ unusedElementSet.forEach(ele -> {
+ File file = new File(backupStorageBase.toFile(), ele.getIdentifier().getIdentification());
+ if (!file.delete())
+ LOGGER.warning("Failed to delete unused file " + file.getName());
+ });
+ }
+
+ /**
* Restore an object collection from the storage base. i.e., restore the save from backup storage.
*
* @param collection the collection to be restored.
@@ -140,28 +174,6 @@ public class IncrementalBackupStorageManager {
return copyCount;
}
- public int cleanUnusedObjects(Iterable<ObjectCollection2> collectionIterable) {
- // construct object list in memory
- Set<String> objects = new HashSet<>();
-// backupStorageBase
-
- for (ObjectCollection2 collection : collectionIterable) {
- for (ObjectElement ele : collection.getElementMap().values()) {
-
- }
- }
- throw new RuntimeException("not impl");
- }
-
- /**
- * Check all objects, return unused ones.
- *
- * @return the unused ones.
- */
- private Map<ObjectIdentifier, File> markUnusedObjects() {
- throw new RuntimeException("not impl");
- }
-
/**
* Check if the backup base contains given element.
*
@@ -174,25 +186,4 @@ public class IncrementalBackupStorageManager {
return (new File(backupStorageBase.toFile(), objectElement.getIdentifier().getIdentification())).exists();
}
- private void lazyLoadStorage() throws IOException {
- if (!loaded) {
- loadStorage();
- loaded = true;
- }
- }
-
- private synchronized void loadStorage() throws IOException {
- map.clear();
- Files.walk(backupStorageBase, 1).forEach(path -> {
- File file = path.toFile();
- ObjectIdentifier identifier = StorageObjectLoader.asIdentifier(file);
- if (identifier == null) {
- map.clear();
- throw new IllegalStateException(String.format(
- "Bad storage object %s: cannot recognize identifier.", file.getName()
- ));
- }
- map.put(identifier, file);
- });
- }
}