diff --git oak-segment-tar/pom.xml oak-segment-tar/pom.xml index 9aea358..3004740 100644 --- oak-segment-tar/pom.xml +++ oak-segment-tar/pom.xml @@ -51,7 +51,7 @@ maven-bundle-plugin - + org.apache.jackrabbit.oak.backup; version=0.0.1 commons-math3, netty-* diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackup.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackup.java index e5803f0..91ad5bb 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackup.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackup.java @@ -16,108 +16,19 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.jackrabbit.oak.backup; -import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; - import java.io.File; import java.io.IOException; -import javax.annotation.Nonnull; - -import com.google.common.base.Stopwatch; -import com.google.common.base.Suppliers; -import org.apache.jackrabbit.oak.segment.Compactor; import org.apache.jackrabbit.oak.segment.Revisions; -import org.apache.jackrabbit.oak.segment.SegmentBufferWriter; -import org.apache.jackrabbit.oak.segment.SegmentNodeState; import org.apache.jackrabbit.oak.segment.SegmentReader; -import org.apache.jackrabbit.oak.segment.SegmentWriter; -import org.apache.jackrabbit.oak.segment.WriterCacheManager; -import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions; import org.apache.jackrabbit.oak.segment.file.FileStore; -import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder; import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; -import org.apache.jackrabbit.oak.segment.file.tooling.BasicReadOnlyBlobStore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FileStoreBackup { - - private static final Logger log = LoggerFactory - .getLogger(FileStoreBackup.class); - - public static boolean USE_FAKE_BLOBSTORE = Boolean - .getBoolean("oak.backup.UseFakeBlobStore"); - - public static void backup(@Nonnull SegmentReader reader, - @Nonnull Revisions revisions, - @Nonnull File destination) - throws IOException, InvalidFileStoreVersionException { - Stopwatch watch = Stopwatch.createStarted(); - SegmentGCOptions gcOptions = SegmentGCOptions.defaultGCOptions() - .setOffline(); - - FileStoreBuilder builder = fileStoreBuilder(destination) - .withDefaultMemoryMapping(); - if (USE_FAKE_BLOBSTORE) { - builder.withBlobStore(new BasicReadOnlyBlobStore()); - } - builder.withGCOptions(gcOptions); - FileStore backup = builder.build(); - SegmentNodeState current = reader.readHeadState(revisions); - try { - int gen = 0; - gen = current.getRecordId().getSegmentId().getGcGeneration(); - SegmentBufferWriter bufferWriter = new SegmentBufferWriter( - backup, - backup.getTracker(), - backup.getReader(), - "b", - gen - ); - SegmentWriter writer = new SegmentWriter( - backup, - backup.getReader(), - backup.getBlobStore(), - new WriterCacheManager.Default(), - bufferWriter, - backup.getBinaryReferenceConsumer() - ); - Compactor compactor = new Compactor(backup.getReader(), writer, - backup.getBlobStore(), Suppliers.ofInstance(false), - gcOptions); - compactor.setContentEqualityCheck(true); - SegmentNodeState head = backup.getHead(); - SegmentNodeState after = compactor.compact(head, current, head); - if (after != null) { - backup.getRevisions().setHead(head.getRecordId(), - after.getRecordId()); - } - } finally { - backup.close(); - backup = null; - } - - FileStoreBuilder builder2 = fileStoreBuilder(destination) - .withDefaultMemoryMapping(); - builder2.withGCOptions(gcOptions); - backup = builder2.build(); - try { - cleanup(backup); - } finally { - backup.close(); - } - watch.stop(); - log.info("Backup finished in {}.", watch); - } - static boolean cleanup(FileStore f) throws IOException { - boolean ok = true; - for (File file : f.cleanup()) { - ok = ok && file.delete(); - } - return true; - } +public interface FileStoreBackup { + void backup(SegmentReader reader, Revisions revisions, File destination) + throws IOException, InvalidFileStoreVersionException; + + boolean cleanup(FileStore f) throws IOException; } diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackupRestore.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackupRestore.java deleted file mode 100644 index 4f4dc54..0000000 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreBackupRestore.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.jackrabbit.oak.backup; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.lang.System.nanoTime; -import static org.apache.jackrabbit.oak.management.ManagementOperation.Status.formatTime; -import static org.apache.jackrabbit.oak.management.ManagementOperation.done; -import static org.apache.jackrabbit.oak.management.ManagementOperation.newManagementOperation; - -import java.io.File; -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; - -import javax.annotation.Nonnull; -import javax.management.openmbean.CompositeData; - -import org.apache.jackrabbit.oak.api.jmx.FileStoreBackupRestoreMBean; -import org.apache.jackrabbit.oak.management.ManagementOperation; -import org.apache.jackrabbit.oak.segment.Revisions; -import org.apache.jackrabbit.oak.segment.SegmentNodeStore; -import org.apache.jackrabbit.oak.segment.SegmentReader; - -/** - * Default implementation of {@link FileStoreBackupRestoreMBean} based on a file. - */ -public class FileStoreBackupRestore implements FileStoreBackupRestoreMBean { - - public static final String BACKUP_OP_NAME = "Backup"; - public static final String RESTORE_OP_NAME = "Restore"; - - private final SegmentNodeStore store; - private final Revisions revisions; - private final SegmentReader reader; - private final File file; - private final Executor executor; - - private ManagementOperation backupOp = done(BACKUP_OP_NAME, ""); - private ManagementOperation restoreOp = done(RESTORE_OP_NAME, ""); - - /** - * @param store store to back up from or restore to - * @param file file to back up to or restore from - * @param executor executor for running the back up or restore operation - */ - public FileStoreBackupRestore( - @Nonnull SegmentNodeStore store, - @Nonnull Revisions revisions, - @Nonnull SegmentReader reader, - @Nonnull File file, - @Nonnull Executor executor) { - this.store = checkNotNull(store); - this.revisions = checkNotNull(revisions); - this.reader = checkNotNull(reader); - this.file = checkNotNull(file); - this.executor = checkNotNull(executor); - } - - @Override - public synchronized CompositeData startBackup() { - if (backupOp.isDone()) { - backupOp = newManagementOperation("Backup", new Callable() { - @Override - public String call() throws Exception { - long t0 = nanoTime(); - FileStoreBackup.backup(reader, revisions, file); - return "Backup completed in " + formatTime(nanoTime() - t0); - } - }); - executor.execute(backupOp); - } - return getBackupStatus(); - } - - @Override - public synchronized CompositeData getBackupStatus() { - return backupOp.getStatus().toCompositeData(); - } - - @Override - public synchronized CompositeData startRestore() { - if (restoreOp.isDone()) { - restoreOp = newManagementOperation("Restore", new Callable() { - @Override - public String call() throws Exception { - long t0 = nanoTime(); - FileStoreRestore.restore(file); - return "Restore completed in " + formatTime(nanoTime() - t0); - } - }); - executor.execute(restoreOp); - } - return getRestoreStatus(); - } - - @Override - public synchronized CompositeData getRestoreStatus() { - return restoreOp.getStatus().toCompositeData(); - } - - @Override - public String checkpoint(long lifetime) { - return store.checkpoint(lifetime); - } - -} diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreRestore.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreRestore.java index 49c5d99..be29c1e 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreRestore.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/FileStoreRestore.java @@ -16,96 +16,14 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.jackrabbit.oak.backup; -import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.defaultGCOptions; -import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; - import java.io.File; import java.io.IOException; -import com.google.common.base.Stopwatch; -import com.google.common.base.Suppliers; -import org.apache.jackrabbit.oak.segment.Compactor; -import org.apache.jackrabbit.oak.segment.SegmentBufferWriter; -import org.apache.jackrabbit.oak.segment.SegmentNodeState; -import org.apache.jackrabbit.oak.segment.SegmentWriter; -import org.apache.jackrabbit.oak.segment.WriterCacheManager; -import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions; -import org.apache.jackrabbit.oak.segment.file.FileStore; import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FileStoreRestore { - - private static final Logger log = LoggerFactory - .getLogger(FileStoreRestore.class); - - static int MAX_FILE_SIZE = 256; - - private static final String JOURNAL_FILE_NAME = "journal.log"; - - public static void restore(File source, File destination) - throws IOException, InvalidFileStoreVersionException { - if (!validFileStore(source)) { - throw new IOException("Folder " + source - + " is not a valid FileStore directory"); - } - - FileStore restore = fileStoreBuilder(source).buildReadOnly(); - Stopwatch watch = Stopwatch.createStarted(); - - FileStore store = fileStoreBuilder(destination).build(); - SegmentNodeState current = store.getHead(); - try { - SegmentNodeState head = restore.getHead(); - int gen = head.getRecordId().getSegmentId().getGcGeneration(); - SegmentBufferWriter bufferWriter = new SegmentBufferWriter( - store, - store.getTracker(), - store.getReader(), - "r", - gen - ); - SegmentWriter writer = new SegmentWriter( - store, - store.getReader(), - store.getBlobStore(), - new WriterCacheManager.Default(), - bufferWriter, - store.getBinaryReferenceConsumer() - ); - SegmentGCOptions gcOptions = defaultGCOptions().setOffline(); - Compactor compactor = new Compactor(store.getReader(), writer, - store.getBlobStore(), Suppliers.ofInstance(false), - gcOptions); - compactor.setContentEqualityCheck(true); - SegmentNodeState after = compactor.compact(current, head, current); - store.getRevisions().setHead(current.getRecordId(), - after.getRecordId()); - } finally { - restore.close(); - store.close(); - } - watch.stop(); - log.info("Restore finished in {}.", watch); - } - - public static void restore(File source) { - log.warn("Restore not available as an online operation."); - } - private static boolean validFileStore(File source) { - if (source == null || !source.isDirectory()) { - return false; - } - for (String f : source.list()) { - if (JOURNAL_FILE_NAME.equals(f)) { - return true; - } - } - return false; - } +public interface FileStoreRestore { + void restore(File source, File destination) throws IOException, InvalidFileStoreVersionException; + void restore(File source); } diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java new file mode 100644 index 0000000..da785dc --- /dev/null +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.jackrabbit.oak.backup.impl; + +import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; + +import java.io.File; +import java.io.IOException; + +import javax.annotation.Nonnull; + +import com.google.common.base.Stopwatch; +import com.google.common.base.Suppliers; + +import org.apache.jackrabbit.oak.backup.FileStoreBackup; +import org.apache.jackrabbit.oak.segment.Compactor; +import org.apache.jackrabbit.oak.segment.Revisions; +import org.apache.jackrabbit.oak.segment.SegmentBufferWriter; +import org.apache.jackrabbit.oak.segment.SegmentNodeState; +import org.apache.jackrabbit.oak.segment.SegmentReader; +import org.apache.jackrabbit.oak.segment.SegmentWriter; +import org.apache.jackrabbit.oak.segment.WriterCacheManager; +import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions; +import org.apache.jackrabbit.oak.segment.file.FileStore; +import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder; +import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; +import org.apache.jackrabbit.oak.segment.file.tooling.BasicReadOnlyBlobStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileStoreBackupImpl implements FileStoreBackup { + + private static final Logger log = LoggerFactory + .getLogger(FileStoreBackupImpl.class); + + public static boolean USE_FAKE_BLOBSTORE = Boolean + .getBoolean("oak.backup.UseFakeBlobStore"); + + @Override + public void backup(@Nonnull SegmentReader reader, + @Nonnull Revisions revisions, + @Nonnull File destination) + throws IOException, InvalidFileStoreVersionException { + Stopwatch watch = Stopwatch.createStarted(); + SegmentGCOptions gcOptions = SegmentGCOptions.defaultGCOptions() + .setOffline(); + + FileStoreBuilder builder = fileStoreBuilder(destination) + .withDefaultMemoryMapping(); + if (USE_FAKE_BLOBSTORE) { + builder.withBlobStore(new BasicReadOnlyBlobStore()); + } + builder.withGCOptions(gcOptions); + FileStore backup = builder.build(); + SegmentNodeState current = reader.readHeadState(revisions); + try { + int gen = 0; + gen = current.getRecordId().getSegmentId().getGcGeneration(); + SegmentBufferWriter bufferWriter = new SegmentBufferWriter( + backup, + backup.getTracker(), + backup.getReader(), + "b", + gen + ); + SegmentWriter writer = new SegmentWriter( + backup, + backup.getReader(), + backup.getBlobStore(), + new WriterCacheManager.Default(), + bufferWriter, + backup.getBinaryReferenceConsumer() + ); + Compactor compactor = new Compactor(backup.getReader(), writer, + backup.getBlobStore(), Suppliers.ofInstance(false), + gcOptions); + compactor.setContentEqualityCheck(true); + SegmentNodeState head = backup.getHead(); + SegmentNodeState after = compactor.compact(head, current, head); + if (after != null) { + backup.getRevisions().setHead(head.getRecordId(), + after.getRecordId()); + } + } finally { + backup.close(); + backup = null; + } + + FileStoreBuilder builder2 = fileStoreBuilder(destination) + .withDefaultMemoryMapping(); + builder2.withGCOptions(gcOptions); + backup = builder2.build(); + try { + cleanup(backup); + } finally { + backup.close(); + } + watch.stop(); + log.info("Backup finished in {}.", watch); + } + + @Override + public boolean cleanup(FileStore f) throws IOException { + boolean ok = true; + for (File file : f.cleanup()) { + ok = ok && file.delete(); + } + return true; + } +} diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupRestoreImpl.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupRestoreImpl.java new file mode 100644 index 0000000..7055c5a --- /dev/null +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupRestoreImpl.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.jackrabbit.oak.backup.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.System.nanoTime; +import static org.apache.jackrabbit.oak.management.ManagementOperation.done; +import static org.apache.jackrabbit.oak.management.ManagementOperation.newManagementOperation; +import static org.apache.jackrabbit.oak.management.ManagementOperation.Status.formatTime; + +import java.io.File; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; + +import javax.annotation.Nonnull; +import javax.management.openmbean.CompositeData; + +import org.apache.jackrabbit.oak.api.jmx.FileStoreBackupRestoreMBean; +import org.apache.jackrabbit.oak.backup.FileStoreBackup; +import org.apache.jackrabbit.oak.backup.FileStoreRestore; +import org.apache.jackrabbit.oak.management.ManagementOperation; +import org.apache.jackrabbit.oak.segment.Revisions; +import org.apache.jackrabbit.oak.segment.SegmentNodeStore; +import org.apache.jackrabbit.oak.segment.SegmentReader; + +/** + * Default implementation of {@link FileStoreBackupRestoreMBean} based on a file. + */ +public class FileStoreBackupRestoreImpl implements FileStoreBackupRestoreMBean { + + public static final String BACKUP_OP_NAME = "Backup"; + public static final String RESTORE_OP_NAME = "Restore"; + + private final SegmentNodeStore store; + private final Revisions revisions; + private final SegmentReader reader; + private final File file; + private final Executor executor; + + private ManagementOperation backupOp = done(BACKUP_OP_NAME, ""); + private ManagementOperation restoreOp = done(RESTORE_OP_NAME, ""); + + private final FileStoreBackup fileStoreBackup; + private final FileStoreRestore fileStoreRestore; + + /** + * @param store store to back up from or restore to + * @param file file to back up to or restore from + * @param executor executor for running the back up or restore operation + */ + public FileStoreBackupRestoreImpl( + @Nonnull SegmentNodeStore store, + @Nonnull Revisions revisions, + @Nonnull SegmentReader reader, + @Nonnull File file, + @Nonnull Executor executor) { + this.store = checkNotNull(store); + this.revisions = checkNotNull(revisions); + this.reader = checkNotNull(reader); + this.file = checkNotNull(file); + this.executor = checkNotNull(executor); + + this.fileStoreBackup = new FileStoreBackupImpl(); + this.fileStoreRestore = new FileStoreRestoreImpl(); + } + + @Override + public synchronized CompositeData startBackup() { + if (backupOp.isDone()) { + backupOp = newManagementOperation("Backup", new Callable() { + @Override + public String call() throws Exception { + long t0 = nanoTime(); + fileStoreBackup.backup(reader, revisions, file); + return "Backup completed in " + formatTime(nanoTime() - t0); + } + }); + executor.execute(backupOp); + } + return getBackupStatus(); + } + + @Override + public synchronized CompositeData getBackupStatus() { + return backupOp.getStatus().toCompositeData(); + } + + @Override + public synchronized CompositeData startRestore() { + if (restoreOp.isDone()) { + restoreOp = newManagementOperation("Restore", new Callable() { + @Override + public String call() throws Exception { + long t0 = nanoTime(); + fileStoreRestore.restore(file); + return "Restore completed in " + formatTime(nanoTime() - t0); + } + }); + executor.execute(restoreOp); + } + return getRestoreStatus(); + } + + @Override + public synchronized CompositeData getRestoreStatus() { + return restoreOp.getStatus().toCompositeData(); + } + + @Override + public String checkpoint(long lifetime) { + return store.checkpoint(lifetime); + } + +} diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java new file mode 100644 index 0000000..e107541 --- /dev/null +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.jackrabbit.oak.backup.impl; + +import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.defaultGCOptions; +import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; + +import java.io.File; +import java.io.IOException; + +import org.apache.jackrabbit.oak.backup.FileStoreRestore; +import org.apache.jackrabbit.oak.segment.Compactor; +import org.apache.jackrabbit.oak.segment.SegmentBufferWriter; +import org.apache.jackrabbit.oak.segment.SegmentNodeState; +import org.apache.jackrabbit.oak.segment.SegmentWriter; +import org.apache.jackrabbit.oak.segment.WriterCacheManager; +import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions; +import org.apache.jackrabbit.oak.segment.file.FileStore; +import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Stopwatch; +import com.google.common.base.Suppliers; + +public class FileStoreRestoreImpl implements FileStoreRestore { + + private static final Logger log = LoggerFactory + .getLogger(FileStoreRestoreImpl.class); + + static int MAX_FILE_SIZE = 256; + + private static final String JOURNAL_FILE_NAME = "journal.log"; + + @Override + public void restore(File source, File destination) + throws IOException, InvalidFileStoreVersionException { + if (!validFileStore(source)) { + throw new IOException("Folder " + source + + " is not a valid FileStore directory"); + } + + FileStore restore = fileStoreBuilder(source).buildReadOnly(); + Stopwatch watch = Stopwatch.createStarted(); + + FileStore store = fileStoreBuilder(destination).build(); + SegmentNodeState current = store.getHead(); + try { + SegmentNodeState head = restore.getHead(); + int gen = head.getRecordId().getSegmentId().getGcGeneration(); + SegmentBufferWriter bufferWriter = new SegmentBufferWriter( + store, + store.getTracker(), + store.getReader(), + "r", + gen + ); + SegmentWriter writer = new SegmentWriter( + store, + store.getReader(), + store.getBlobStore(), + new WriterCacheManager.Default(), + bufferWriter, + store.getBinaryReferenceConsumer() + ); + SegmentGCOptions gcOptions = defaultGCOptions().setOffline(); + Compactor compactor = new Compactor(store.getReader(), writer, + store.getBlobStore(), Suppliers.ofInstance(false), + gcOptions); + compactor.setContentEqualityCheck(true); + SegmentNodeState after = compactor.compact(current, head, current); + store.getRevisions().setHead(current.getRecordId(), + after.getRecordId()); + } finally { + restore.close(); + store.close(); + } + watch.stop(); + log.info("Restore finished in {}.", watch); + } + + @Override + public void restore(File source) { + log.warn("Restore not available as an online operation."); + } + + private boolean validFileStore(File source) { + if (source == null || !source.isDirectory()) { + return false; + } + for (String f : source.list()) { + if (JOURNAL_FILE_NAME.equals(f)) { + return true; + } + } + return false; + } +} diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Backup.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Backup.java index 351e288..8fc897a 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Backup.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Backup.java @@ -25,6 +25,7 @@ import java.io.File; import java.io.IOException; import org.apache.jackrabbit.oak.backup.FileStoreBackup; +import org.apache.jackrabbit.oak.backup.impl.FileStoreBackupImpl; import org.apache.jackrabbit.oak.segment.file.FileStore; import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; @@ -51,10 +52,13 @@ public class Backup implements Runnable { private File target; - private boolean fakeBlobStore = FileStoreBackup.USE_FAKE_BLOBSTORE; + private boolean fakeBlobStore = FileStoreBackupImpl.USE_FAKE_BLOBSTORE; + + private final FileStoreBackup fileStoreBackup; private Builder() { // Prevent external instantiation. + this.fileStoreBackup = new FileStoreBackupImpl(); } /** @@ -94,7 +98,7 @@ public class Backup implements Runnable { this.fakeBlobStore = fakeBlobStore; return this; } - + /** * Create an executable version of the {@link Backup} command. * @@ -109,21 +113,21 @@ public class Backup implements Runnable { } private final File source; - private final File target; - private final boolean fakeBlobStore; + private final FileStoreBackup fileStoreBackup; private Backup(Builder builder) { this.source = builder.source; this.target = builder.target; this.fakeBlobStore = builder.fakeBlobStore; + this.fileStoreBackup = builder.fileStoreBackup; } @Override public void run() { try (FileStore fs = newFileStore()) { - FileStoreBackup.backup(fs.getReader(), fs.getRevisions(), target); + fileStoreBackup.backup(fs.getReader(), fs.getRevisions(), target); } catch (Exception e) { e.printStackTrace(); } diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Restore.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Restore.java index 56d41a8..24e30f5 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Restore.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Restore.java @@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.io.File; import org.apache.jackrabbit.oak.backup.FileStoreRestore; +import org.apache.jackrabbit.oak.backup.impl.FileStoreRestoreImpl; /** * Restore a backup of a segment store into an existing segment store. @@ -43,11 +44,12 @@ public class Restore implements Runnable { public static class Builder { private File source; - private File target; + private final FileStoreRestore fileStoreRestore; private Builder() { // Prevent external instantiation. + this.fileStoreRestore = new FileStoreRestoreImpl(); } /** @@ -86,18 +88,19 @@ public class Restore implements Runnable { } private final File source; - private final File target; + private final FileStoreRestore fileStoreRestore; private Restore(Builder builder) { this.source = builder.source; this.target = builder.target; + this.fileStoreRestore = builder.fileStoreRestore; } @Override public void run() { try { - FileStoreRestore.restore(source, target); + fileStoreRestore.restore(source, target); } catch (Exception e) { e.printStackTrace(); } diff --git oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/backup/FileStoreBackupTest.java oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/backup/FileStoreBackupTest.java index a0b302c..64f3c79 100644 --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/backup/FileStoreBackupTest.java +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/backup/FileStoreBackupTest.java @@ -30,6 +30,8 @@ import java.util.Random; import org.apache.jackrabbit.oak.Oak; import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.backup.impl.FileStoreBackupImpl; +import org.apache.jackrabbit.oak.backup.impl.FileStoreRestoreImpl; import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent; import org.apache.jackrabbit.oak.segment.SegmentNodeStore; import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders; @@ -64,20 +66,23 @@ public class FileStoreBackupTest { FileStore source = newFileStore(src); SegmentNodeStore store = SegmentNodeStoreBuilders.builder(source) .build(); + + FileStoreBackup fsb = new FileStoreBackupImpl(); + try { init(store); source.flush(); - FileStoreBackup.backup(source.getReader(), source.getRevisions(), destination); + fsb.backup(source.getReader(), source.getRevisions(), destination); compare(source, destination); addTestContent(store); source.flush(); - FileStoreBackup.backup(source.getReader(), source.getRevisions(), destination); + fsb.backup(source.getReader(), source.getRevisions(), destination); compare(source, destination); source.compact(); - FileStoreBackup.cleanup(source); - FileStoreBackup.backup(source.getReader(), source.getRevisions(), destination); + fsb.cleanup(source); + fsb.backup(source.getReader(), source.getRevisions(), destination); compare(source, destination); } finally { source.close(); @@ -89,12 +94,15 @@ public class FileStoreBackupTest { FileStore source = newFileStore(src); SegmentNodeStore store = SegmentNodeStoreBuilders.builder(source) .build(); + FileStoreBackup fsb = new FileStoreBackupImpl(); + FileStoreRestore fsr = new FileStoreRestoreImpl(); + init(store); source.flush(); - FileStoreBackup.backup(source.getReader(), source.getRevisions(), destination); + fsb.backup(source.getReader(), source.getRevisions(), destination); source.close(); - FileStoreRestore.restore(destination, src); + fsr.restore(destination, src); source = newFileStore(src); compare(source, destination); source.close();