Index: oak-core/pom.xml =================================================================== --- oak-core/pom.xml (revision 1719058) +++ oak-core/pom.xml (working copy) @@ -69,6 +69,7 @@ org.apache.jackrabbit.oak.plugins.observation, org.apache.jackrabbit.oak.plugins.observation.filter, org.apache.jackrabbit.oak.plugins.segment, + org.apache.jackrabbit.oak.plugins.segment.backup, org.apache.jackrabbit.oak.plugins.segment.http, org.apache.jackrabbit.oak.plugins.segment.file, org.apache.jackrabbit.oak.plugins.tree, Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/BackupStrategy.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/BackupStrategy.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/BackupStrategy.java (working copy) @@ -0,0 +1,29 @@ +/* + * 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.plugins.backup; + +import org.apache.jackrabbit.oak.spi.state.NodeStore; + +import java.io.File; +import java.io.IOException; + +public interface BackupStrategy { + + void backup(NodeStore store, File destination) throws IOException; + +} Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/BackupStrategy.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackup.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackup.java (revision 1719058) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackup.java (working copy) @@ -1,94 +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.plugins.backup; - -import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE; - -import java.io.File; -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import com.google.common.collect.ImmutableMap; -import org.apache.jackrabbit.oak.plugins.segment.Compactor; -import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeBuilder; -import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState; -import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; -import org.apache.jackrabbit.oak.spi.state.NodeState; -import org.apache.jackrabbit.oak.spi.state.NodeStore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FileStoreBackup { - - private static final Logger log = LoggerFactory - .getLogger(FileStoreBackup.class); - - private static final long DEFAULT_LIFETIME = TimeUnit.HOURS.toMillis(1); - - static int MAX_FILE_SIZE = 256; - - public static void backup(NodeStore store, File destination) - throws IOException { - long s = System.currentTimeMillis(); - - // 1. create a new checkpoint with the current state - String checkpoint = store.checkpoint(DEFAULT_LIFETIME, ImmutableMap.of( - "creator", FileStoreBackup.class.getSimpleName(), - "thread", Thread.currentThread().getName())); - NodeState current = store.retrieve(checkpoint); - if (current == null) { - // unable to retrieve the checkpoint; use root state instead - current = store.getRoot(); - } - - // 2. init filestore - FileStore backup = new FileStore(destination, MAX_FILE_SIZE, false); - try { - SegmentNodeState state = backup.getHead(); - NodeState before = null; - String beforeCheckpoint = state.getString("checkpoint"); - if (beforeCheckpoint == null) { - // 3.1 no stored checkpoint, so do the initial full backup - before = EMPTY_NODE; - } else { - // 3.2 try to retrieve the previously backed up checkpoint - before = store.retrieve(beforeCheckpoint); - if (before == null) { - // the previous checkpoint is no longer available, - // so use the backed up state as the basis of the - // incremental backup diff - before = state.getChildNode("root"); - } - } - - Compactor compactor = new Compactor(backup); - SegmentNodeState after = compactor.compact(before, current); - - // 4. commit the backup - SegmentNodeBuilder builder = state.builder(); - builder.setProperty("checkpoint", checkpoint); - builder.setChildNode("root", after); - backup.setHead(state, builder.getNodeState()); - } finally { - backup.close(); - } - - log.debug("Backup finished in {} ms.", System.currentTimeMillis() - s); - } -} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackupRestore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackupRestore.java (revision 1719058) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackupRestore.java (working copy) @@ -19,40 +19,42 @@ package org.apache.jackrabbit.oak.plugins.backup; +import org.apache.jackrabbit.oak.management.ManagementOperation; +import org.apache.jackrabbit.oak.spi.state.NodeStore; + +import javax.annotation.Nonnull; +import javax.management.openmbean.CompositeData; +import java.io.File; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; + 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 static org.apache.jackrabbit.oak.plugins.backup.FileStoreBackup.backup; -import static org.apache.jackrabbit.oak.plugins.backup.FileStoreRestore.restore; -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.management.ManagementOperation; -import org.apache.jackrabbit.oak.spi.state.NodeStore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Default implementation of {@link FileStoreBackupRestoreMBean} based on a file. */ public class FileStoreBackupRestore implements FileStoreBackupRestoreMBean { - private static final Logger log = LoggerFactory.getLogger(FileStoreBackupRestore.class); public static final String BACKUP_OP_NAME = "Backup"; + public static final String RESTORE_OP_NAME = "Restore"; private final NodeStore store; + private final File file; + private final Executor executor; + private final BackupStrategy backupStrategy; + + private final RestoreStrategy restoreStrategy; + private ManagementOperation backupOp = done(BACKUP_OP_NAME, ""); + private ManagementOperation restoreOp = done(RESTORE_OP_NAME, ""); /** @@ -63,10 +65,14 @@ public FileStoreBackupRestore( @Nonnull NodeStore store, @Nonnull File file, - @Nonnull Executor executor) { + @Nonnull Executor executor, + BackupStrategy backupStrategy, + RestoreStrategy restoreStrategy) { this.store = checkNotNull(store); this.file = checkNotNull(file); this.executor = checkNotNull(executor); + this.backupStrategy = checkNotNull(backupStrategy); + this.restoreStrategy = checkNotNull(restoreStrategy); } @Override @@ -76,7 +82,7 @@ @Override public String call() throws Exception { long t0 = nanoTime(); - backup(store, file); + backupStrategy.backup(store, file); return "Backup completed in " + formatTime(nanoTime() - t0); } }); @@ -97,7 +103,7 @@ @Override public String call() throws Exception { long t0 = nanoTime(); - restore(file, store); + restoreStrategy.restore(file, store); return "Restore completed in " + formatTime(nanoTime() - t0); } }); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreRestore.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreRestore.java (revision 1719058) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreRestore.java (working copy) @@ -1,97 +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.plugins.backup; - -import java.io.File; -import java.io.IOException; - -import org.apache.jackrabbit.oak.api.CommitFailedException; -import org.apache.jackrabbit.oak.plugins.segment.Compactor; -import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeBuilder; -import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState; -import org.apache.jackrabbit.oak.plugins.segment.SegmentStore; -import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; -import org.apache.jackrabbit.oak.spi.commit.CommitInfo; -import org.apache.jackrabbit.oak.spi.commit.EmptyHook; -import org.apache.jackrabbit.oak.spi.state.NodeState; -import org.apache.jackrabbit.oak.spi.state.NodeStore; -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, NodeStore store) - throws IOException, CommitFailedException { - // 1. verify that this is an actual filestore - if (!validFileStore(source)) { - throw new IOException("Folder " + source - + " is not a valid FileStore directory"); - } - - // 2. init filestore - FileStore restore = new FileStore(source, MAX_FILE_SIZE, false); - try { - SegmentNodeState state = restore.getHead(); - restore(state.getChildNode("root"), store, restore); - } finally { - restore.close(); - } - } - - private static void restore(NodeState source, NodeStore store, - SegmentStore restore) throws CommitFailedException { - long s = System.currentTimeMillis(); - NodeState current = store.getRoot(); - RestoreCompactor compactor = new RestoreCompactor(restore); - SegmentNodeBuilder builder = compactor.process(current, source, current); - store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); - log.debug("Restore finished in {} ms.", System.currentTimeMillis() - s); - } - - private static class RestoreCompactor extends Compactor { - - public RestoreCompactor(SegmentStore store) { - super(store); - } - - @Override - protected SegmentNodeBuilder process(NodeState before, NodeState after, NodeState onto) { - return super.process(before, after, onto); - } - } - - 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; - } -} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/RestoreStrategy.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/RestoreStrategy.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/RestoreStrategy.java (working copy) @@ -0,0 +1,30 @@ +/* + * 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.plugins.backup; + +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.spi.state.NodeStore; + +import java.io.File; +import java.io.IOException; + +public interface RestoreStrategy { + + void restore(File source, NodeStore store) throws IOException, CommitFailedException; + +} Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/RestoreStrategy.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/package-info.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/package-info.java (revision 1719058) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/backup/package-info.java (working copy) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.0") +@Version("2.0.0") @Export(optional = "provide:=true") package org.apache.jackrabbit.oak.plugins.backup; Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategy.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategy.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategy.java (working copy) @@ -0,0 +1,94 @@ +/* + * 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.plugins.segment.backup; + +import com.google.common.collect.ImmutableMap; +import org.apache.jackrabbit.oak.plugins.backup.BackupStrategy; +import org.apache.jackrabbit.oak.plugins.segment.Compactor; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeBuilder; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState; +import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE; + +public class FileStoreBackupStrategy implements BackupStrategy { + + private static final Logger log = LoggerFactory.getLogger(FileStoreBackupStrategy.class); + + private static final long DEFAULT_LIFETIME = TimeUnit.HOURS.toMillis(1); + + private static final int MAX_FILE_SIZE = 256; + + @Override + public void backup(NodeStore store, File destination) throws IOException { + long s = System.currentTimeMillis(); + + // 1. create a new checkpoint with the current state + String checkpoint = store.checkpoint(DEFAULT_LIFETIME, ImmutableMap.of( + "creator", getClass().getSimpleName(), + "thread", Thread.currentThread().getName())); + NodeState current = store.retrieve(checkpoint); + if (current == null) { + // unable to retrieve the checkpoint; use root state instead + current = store.getRoot(); + } + + // 2. init filestore + FileStore backup = new FileStore(destination, MAX_FILE_SIZE, false); + try { + SegmentNodeState state = backup.getHead(); + NodeState before = null; + String beforeCheckpoint = state.getString("checkpoint"); + if (beforeCheckpoint == null) { + // 3.1 no stored checkpoint, so do the initial full backup + before = EMPTY_NODE; + } else { + // 3.2 try to retrieve the previously backed up checkpoint + before = store.retrieve(beforeCheckpoint); + if (before == null) { + // the previous checkpoint is no longer available, + // so use the backed up state as the basis of the + // incremental backup diff + before = state.getChildNode("root"); + } + } + + Compactor compactor = new Compactor(backup); + SegmentNodeState after = compactor.compact(before, current); + + // 4. commit the backup + SegmentNodeBuilder builder = state.builder(); + builder.setProperty("checkpoint", checkpoint); + builder.setChildNode("root", after); + backup.setHead(state, builder.getNodeState()); + } finally { + backup.close(); + } + + log.debug("Backup finished in {} ms.", System.currentTimeMillis() - s); + } + +} Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategy.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreRestoreStrategy.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreRestoreStrategy.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreRestoreStrategy.java (working copy) @@ -0,0 +1,98 @@ +/* + * 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.plugins.segment.backup; + +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.plugins.backup.RestoreStrategy; +import org.apache.jackrabbit.oak.plugins.segment.Compactor; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeBuilder; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState; +import org.apache.jackrabbit.oak.plugins.segment.SegmentStore; +import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; +import org.apache.jackrabbit.oak.spi.commit.CommitInfo; +import org.apache.jackrabbit.oak.spi.commit.EmptyHook; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; + +public class FileStoreRestoreStrategy implements RestoreStrategy { + + private static final Logger log = LoggerFactory.getLogger(FileStoreRestoreStrategy.class); + + private static final String JOURNAL_FILE_NAME = "journal.log"; + + private static final int MAX_FILE_SIZE = 256; + + @Override + public void restore(File source, NodeStore store) throws IOException, CommitFailedException { + // 1. verify that this is an actual filestore + if (!validFileStore(source)) { + throw new IOException("Folder " + source + + " is not a valid FileStore directory"); + } + + // 2. init filestore + FileStore restore = new FileStore(source, MAX_FILE_SIZE, false); + try { + SegmentNodeState state = restore.getHead(); + restore(state.getChildNode("root"), store, restore); + } finally { + restore.close(); + } + } + + private static void restore(NodeState source, NodeStore store, + SegmentStore restore) throws CommitFailedException { + long s = System.currentTimeMillis(); + NodeState current = store.getRoot(); + RestoreCompactor compactor = new RestoreCompactor(restore); + SegmentNodeBuilder builder = compactor.process(current, source, current); + store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); + log.debug("Restore finished in {} ms.", System.currentTimeMillis() - s); + } + + private static class RestoreCompactor extends Compactor { + + public RestoreCompactor(SegmentStore store) { + super(store); + } + + @Override + protected SegmentNodeBuilder process(NodeState before, NodeState after, NodeState onto) { + return super.process(before, after, onto); + } + + } + + 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; + } + +} Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreRestoreStrategy.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/package-info.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/package-info.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/package-info.java (working copy) @@ -0,0 +1,21 @@ +/* + * 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. + */ + +@Version("1.0.0") +package org.apache.jackrabbit.oak.plugins.segment.backup; + +import aQute.bnd.annotation.Version; \ No newline at end of file Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/backup/package-info.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackupTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackupTest.java (revision 1719058) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/backup/FileStoreBackupTest.java (working copy) @@ -1,163 +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.plugins.backup; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -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.plugins.nodetype.write.InitialContent; -import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore; -import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; -import org.apache.jackrabbit.oak.spi.commit.CommitInfo; -import org.apache.jackrabbit.oak.spi.commit.EmptyHook; -import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider; -import org.apache.jackrabbit.oak.spi.state.NodeBuilder; -import org.apache.jackrabbit.oak.spi.state.NodeStore; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.apache.commons.io.FileUtils.deleteQuietly; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class FileStoreBackupTest { - - private File src; - private File destination; - - @Before - public void before() { - long run = System.currentTimeMillis(); - File root = new File("target"); - src = new File(root, "tar-src-" + run); - destination = new File(root, "tar-dest-" + run); - } - - @After - public void after() { - deleteQuietly(src); - deleteQuietly(destination); - } - - @Test - public void testBackup() throws Exception { - FileStore source = new FileStore(src, 8, false); - - NodeStore store = new SegmentNodeStore(source); - init(store); - - // initial content - FileStoreBackup.backup(store, destination); - - compare(store, destination); - - addTestContent(store); - FileStoreBackup.backup(store, destination); - compare(store, destination); - - source.close(); - } - - @Test - public void testRestore() throws Exception { - FileStore source = new FileStore(src, 8, false); - - NodeStore store = new SegmentNodeStore(source); - init(store); - - // initial content - FileStoreBackup.backup(store, destination); - - addTestContent(store); - - FileStoreRestore.restore(destination, store); - - compare(store, destination); - - source.close(); - } - - private static void addTestContent(NodeStore store) - throws CommitFailedException { - NodeBuilder builder = store.getRoot().builder(); - builder.child("test-backup"); - builder.child("root"); // make sure we don't backup the super-root - store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); - } - - private static void compare(NodeStore store, File destination) - throws IOException { - FileStore backup = new FileStore(destination, 8, false); - assertEquals(store.getRoot(), new SegmentNodeStore(backup).getRoot()); - backup.close(); - } - - private static void init(NodeStore store) { - new Oak(store).with(new OpenSecurityProvider()) - .with(new InitialContent()).createContentRepository(); - } - - public void testSharedContent() throws Exception { - FileStore source = new FileStore(src, 256, false); - - NodeStore store = new SegmentNodeStore(source); - - // ~100k - Blob blob = store.createBlob(new ByteArrayInputStream(new byte[100000])); - - NodeBuilder builder = store.getRoot().builder(); - NodeBuilder c1 = builder.child("test-backup"); - c1.setProperty("blob", blob); - NodeBuilder c2 = builder.child("test-backup2"); - c2.setProperty("blob", blob); - store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); - - FileStoreBackup.backup(store, destination); - compare(store, destination); - source.close(); - - Map expected = new HashMap(); - for (File f : src.listFiles()) { - if (f.getName().endsWith(".tar")) { - expected.put(f.getName(), f.length()); - } - } - - for (File f : destination.listFiles()) { - if (!f.getName().endsWith(".tar")) { - continue; - } - assertTrue(f.getName() + " is missing from the backup", - expected.containsKey(f.getName())); - assertTrue( - f.getName() + " is expected to have size <= " - + expected.get(f.getName()) + " actually is " - + f.length(), - f.length() <= expected.get(f.getName())); - } - - } -} Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategyTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategyTest.java (working copy) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/backup/FileStoreBackupStrategyTest.java (working copy) @@ -16,14 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.jackrabbit.oak.plugins.backup; +package org.apache.jackrabbit.oak.plugins.segment.backup; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - import org.apache.jackrabbit.oak.Oak; import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.CommitFailedException; @@ -39,11 +33,17 @@ import org.junit.Before; import org.junit.Test; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + import static org.apache.commons.io.FileUtils.deleteQuietly; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -public class FileStoreBackupTest { +public class FileStoreBackupStrategyTest { private File src; private File destination; @@ -70,12 +70,12 @@ init(store); // initial content - FileStoreBackup.backup(store, destination); + backup(store, destination); compare(store, destination); addTestContent(store); - FileStoreBackup.backup(store, destination); + backup(store, destination); compare(store, destination); source.close(); @@ -89,11 +89,11 @@ init(store); // initial content - FileStoreBackup.backup(store, destination); + backup(store, destination); addTestContent(store); - FileStoreRestore.restore(destination, store); + restore(destination, store); compare(store, destination); @@ -135,7 +135,7 @@ c2.setProperty("blob", blob); store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); - FileStoreBackup.backup(store, destination); + backup(store, destination); compare(store, destination); source.close(); @@ -160,4 +160,13 @@ } } + + private static void backup(NodeStore store, File destination) throws IOException { + new FileStoreBackupStrategy().backup(store, destination); + } + + private static void restore(File source, NodeStore store) throws IOException, CommitFailedException { + new FileStoreRestoreStrategy().restore(source, store); + } + } Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java (revision 1719058) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java (working copy) @@ -16,44 +16,6 @@ */ package org.apache.jackrabbit.oak.run; -import static com.google.common.collect.Sets.newHashSet; -import static java.util.Arrays.asList; -import static org.apache.commons.io.FileUtils.byteCountToDisplaySize; -import static org.apache.jackrabbit.oak.checkpoint.Checkpoints.CP; -import static org.apache.jackrabbit.oak.plugins.segment.RecordType.NODE; -import static org.apache.jackrabbit.oak.plugins.segment.file.FileStore.newFileStore; -import static org.apache.jackrabbit.oak.plugins.segment.file.tooling.ConsistencyChecker.checkConsistency; -import static org.slf4j.LoggerFactory.getLogger; - -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.jcr.Repository; - import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import com.google.common.base.Joiner; @@ -71,6 +33,7 @@ import joptsimple.OptionSpec; import org.apache.commons.io.FileUtils; import org.apache.jackrabbit.oak.Oak; +import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.benchmark.BenchmarkRunner; import org.apache.jackrabbit.oak.checkpoint.Checkpoints; @@ -84,8 +47,6 @@ import org.apache.jackrabbit.oak.http.OakServlet; import org.apache.jackrabbit.oak.jcr.Jcr; import org.apache.jackrabbit.oak.json.JsopDiff; -import org.apache.jackrabbit.oak.plugins.backup.FileStoreBackup; -import org.apache.jackrabbit.oak.plugins.backup.FileStoreRestore; import org.apache.jackrabbit.oak.plugins.document.DocumentMK; import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreHelper; @@ -108,6 +69,8 @@ import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState; import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore; import org.apache.jackrabbit.oak.plugins.segment.SegmentTracker; +import org.apache.jackrabbit.oak.plugins.segment.backup.FileStoreBackupStrategy; +import org.apache.jackrabbit.oak.plugins.segment.backup.FileStoreRestoreStrategy; import org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy; import org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.CleanupType; import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; @@ -131,6 +94,43 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import javax.jcr.Repository; +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Queue; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.google.common.collect.Sets.newHashSet; +import static java.util.Arrays.asList; +import static org.apache.commons.io.FileUtils.byteCountToDisplaySize; +import static org.apache.jackrabbit.oak.checkpoint.Checkpoints.CP; +import static org.apache.jackrabbit.oak.plugins.segment.RecordType.NODE; +import static org.apache.jackrabbit.oak.plugins.segment.file.FileStore.newFileStore; +import static org.apache.jackrabbit.oak.plugins.segment.file.tooling.ConsistencyChecker.checkConsistency; +import static org.slf4j.LoggerFactory.getLogger; + public final class Main { public static final int PORT = 8080; @@ -270,7 +270,7 @@ String h = "backup { /path/to/oak/repository | mongodb://host:port/database } "; try { NodeStore store = bootstrapNodeStore(args, closer, h); - FileStoreBackup.backup(store, new File(args[1])); + backup(store, new File(args[1])); } catch (Throwable e) { throw closer.rethrow(e); } finally { @@ -278,12 +278,16 @@ } } + private static void backup(NodeStore store, File path) throws IOException { + new FileStoreBackupStrategy().backup(store, path); + } + private static void restore(String[] args) throws IOException { Closer closer = Closer.create(); String h = "restore { /path/to/oak/repository | mongodb://host:port/database } "; try { NodeStore store = bootstrapNodeStore(args, closer, h); - FileStoreRestore.restore(new File(args[1]), store); + restore(new File(args[1]), store); } catch (Throwable e) { throw closer.rethrow(e); } finally { @@ -291,6 +295,10 @@ } } + private static void restore(File source, NodeStore store) throws IOException, CommitFailedException { + new FileStoreRestoreStrategy().restore(source, store); + } + //TODO react to state changes of FailoverClient (triggered via JMX), once the state model of FailoverClient is complete. private static class ScheduledSyncService extends AbstractScheduledService {