Skip to content

Commit

Permalink
feature: native copy-on-write support
Browse files Browse the repository at this point in the history
  • Loading branch information
keuin committed Jan 19, 2024
1 parent 61aa66b commit 62ae677
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import com.keuin.kbackupfabric.backup.incremental.identifier.ObjectIdentifier;
import com.keuin.kbackupfabric.util.FilesystemUtil;
import com.keuin.kbackupfabric.util.PrintUtil;
import com.keuin.kbackupfabric.util.cow.FileCopier;
import com.keuin.kbackupfabric.util.cow.FileCowCopier;
import com.keuin.kbackupfabric.util.cow.FileEagerCopier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.logging.Logger;
Expand All @@ -27,9 +29,21 @@ public class IncrementalBackupStorageManager {
private final Logger logger = Logger.getLogger(IncrementalBackupStorageManager.class.getName());
private final Path backupStorageBase;
private final Logger LOGGER = Logger.getLogger(IncrementalBackupStorageManager.class.getName());
private FileCopier copier = null;

public IncrementalBackupStorageManager(Path backupStorageBase) {
this.backupStorageBase = backupStorageBase;
try {
this.copier = FileCowCopier.getInstance();
} catch (Exception | UnsatisfiedLinkError ex) {
PrintUtil.error("Failed to initialize kbackup-cow: " + ex + ex.getMessage());
this.copier = new FileEagerCopier();
}
if (this.copier.isCow()) {
PrintUtil.info("Copy-on-write is enabled");
} else {
PrintUtil.info("Copy-on-write is disabled");
}
}

/**
Expand Down Expand Up @@ -85,7 +99,7 @@ IncCopyResult addObjectCollection(ObjectCollection2 collection, File collectionB
if (!contains(entry.getValue())) {
// element does not exist. copy.
logger.fine("Copy new file `" + copySourceFile.getName() + "`.");
Files.copy(copySourceFile.toPath(), copyDestination.toPath());
copier.copy(copyDestination.getAbsolutePath(), copySourceFile.getAbsolutePath());
copyCount = copyCount.addWith(new IncCopyResult(1, 1, fileBytes, fileBytes));
} else {
// element exists (file reused). Just update the stat info
Expand Down Expand Up @@ -198,7 +212,7 @@ public int restoreObjectCollection(ObjectCollection2 collection, File collection
}
}

Files.copy(copySource.toPath(), copyTarget.toPath());
copier.copy(copyTarget.getAbsolutePath(), copySource.getAbsolutePath());
++copyCount;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public ConfiguredIncrementalBackupMethod(String backupIndexFileName, String leve
@Override
public IncrementalBackupFeedback backup() {
final int hashFactoryThreads = ThreadingUtil.getRecommendedThreadCount(); // how many threads do we use to generate the hash tree
LOGGER.info("Threads: " + hashFactoryThreads);
PrintUtil.info("Threads: " + hashFactoryThreads);

// needed in abort progress
File levelPathFile = new File(levelPath);
Expand Down Expand Up @@ -99,6 +99,7 @@ public IncrementalBackupFeedback backup() {
PrintUtil.info("Incremental backup finished.");
feedback = new IncrementalBackupFeedback(true, copyResult);
} catch (IOException e) {
PrintUtil.error("Incremental backup failed: " + e + e.getMessage());
feedback = new IncrementalBackupFeedback(e);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.keuin.kbackupfabric.util.cow;

import java.io.IOException;

public interface FileCopier {
void copy(String dst, String src) throws IOException;

boolean isCow();
}
41 changes: 41 additions & 0 deletions src/main/java/com/keuin/kbackupfabric/util/cow/FileCowCopier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.keuin.kbackupfabric.util.cow;

import com.keuin.kbackupfabric.util.PrintUtil;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

public final class FileCowCopier {
private static final AtomicBoolean initialized = new AtomicBoolean(false);

static {
try {
System.loadLibrary("kbackup_cow");
} catch (SecurityException | UnsatisfiedLinkError ignored) {
}
}

public static native void init();

public static native void copy(String dst, String src) throws IOException;

public static native String getVersion();

public static FileCopier getInstance() {
if (initialized.compareAndSet(false, true)) {
FileCowCopier.init();
PrintUtil.info("kbackup-cow version: " + FileCowCopier.getVersion());
}
return new FileCopier() {
@Override
public void copy(String dst, String src) throws IOException {
FileCowCopier.copy(dst, src);
}

@Override
public boolean isCow() {
return true;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.keuin.kbackupfabric.util.cow;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileEagerCopier implements FileCopier {
@Override
public void copy(String dst, String src) throws IOException {
Files.copy(Paths.get(src), Paths.get(dst));
}

@Override
public boolean isCow() {
return false;
}
}

0 comments on commit 62ae677

Please sign in to comment.