diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java index af2ade6..30dd5b2 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java @@ -269,6 +269,31 @@ public class SegmentNodeStore implements NodeStore, Observable { return head.get(); } + public boolean setSuperRoot(@Nonnull NodeBuilder builder) { + checkArgument(builder instanceof SegmentNodeBuilder); + if (commitSemaphore.tryAcquire()) { + try { + SegmentNodeBuilder snb = (SegmentNodeBuilder) builder; + SegmentNodeState state = head.get(); + + if (!state.getRecordId().equals(((SegmentNodeState) snb.getBaseState()).getRecordId())) { + throw new IllegalArgumentException("The new head is out of date"); + } + + SegmentNodeState newState = snb.getNodeState(); + if (revisions.setHead(state.getRecordId(), newState.getRecordId())) { + refreshHead(); + return true; + } else { + return false; + } + } finally { + commitSemaphore.release(); + } + } + return false; + } + @Override public NodeState merge( @Nonnull NodeBuilder builder, @Nonnull CommitHook commitHook, diff --git a/oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java b/oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java index c5efa1a..67fcb76 100644 --- a/oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java +++ b/oak-segment/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java @@ -280,6 +280,31 @@ public class SegmentNodeStore implements NodeStore, Observable { return head.get(); } + public boolean setSuperRoot(@Nonnull NodeBuilder builder) { + checkArgument(builder instanceof SegmentNodeBuilder); + if (commitSemaphore.tryAcquire()) { + try { + SegmentNodeBuilder snb = (SegmentNodeBuilder) builder; + SegmentNodeState state = head.get(); + + if (!state.getRecordId().equals(((SegmentNodeState) snb.getBaseState()).getRecordId())) { + throw new IllegalArgumentException("The new head is out of date"); + } + + SegmentNodeState newState = snb.getNodeState(); + if (store.setHead(state, newState)) { + refreshHead(); + return true; + } else { + return false; + } + } finally { + commitSemaphore.release(); + } + } + return false; + } + @Override public NodeState merge( @Nonnull NodeBuilder builder, @Nonnull CommitHook commitHook, diff --git a/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java b/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java index e4a7873..5d62333 100755 --- a/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java +++ b/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java @@ -263,7 +263,10 @@ public class RepositorySidegrade { private void copyState(NodeState sourceRoot, NodeBuilder targetRoot) throws CommitFailedException { copyWorkspace(sourceRoot, targetRoot); - removeCheckpointReferences(targetRoot); + if (!copyCheckpoints()) { + LOG.info("Copying checkpoints is not supported for this combination of node stores"); + removeCheckpointReferences(targetRoot); + } if (!versionCopyConfiguration.skipOrphanedVersionsCopy()) { copyVersionStorage(sourceRoot, targetRoot, versionCopyConfiguration); } @@ -296,4 +299,39 @@ public class RepositorySidegrade { copyProperties(sourceRoot, targetRoot); } } + + private boolean copyCheckpoints() { + NodeState srcSuperRoot = null; + NodeState dstSuperRoot = null; + + if (source instanceof org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore) { + srcSuperRoot = ((org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore) source).getSuperRoot(); + } else if (source instanceof org.apache.jackrabbit.oak.segment.SegmentNodeStore) { + srcSuperRoot = ((org.apache.jackrabbit.oak.segment.SegmentNodeStore) source).getSuperRoot(); + } + + if (target instanceof org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore) { + dstSuperRoot = ((org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore) target).getSuperRoot(); + } else if (target instanceof org.apache.jackrabbit.oak.segment.SegmentNodeStore) { + dstSuperRoot = ((org.apache.jackrabbit.oak.segment.SegmentNodeStore) target).getSuperRoot(); + } + + if (srcSuperRoot == null || dstSuperRoot == null) { + return false; + } + + NodeBuilder builder = dstSuperRoot.builder(); + + NodeStateCopier.builder() + .include("/checkpoints") + .copy(srcSuperRoot, builder); + + if (target instanceof org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore) { + return ((org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore) target).setSuperRoot(builder); + } else if (target instanceof org.apache.jackrabbit.oak.segment.SegmentNodeStore) { + return ((org.apache.jackrabbit.oak.segment.SegmentNodeStore) target).setSuperRoot(builder); + } else { + return false; + } + } } \ No newline at end of file diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegradeTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegradeTest.java index 17ec1de..552b4a0 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegradeTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegradeTest.java @@ -61,14 +61,9 @@ import org.apache.jackrabbit.api.JackrabbitWorkspace; import org.apache.jackrabbit.oak.Oak; import org.apache.jackrabbit.oak.jcr.Jcr; import org.apache.jackrabbit.oak.plugins.index.IndexConstants; -import org.apache.jackrabbit.oak.segment.SegmentNodeStore; import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders; import org.apache.jackrabbit.oak.segment.memory.MemoryStore; -import org.apache.jackrabbit.oak.spi.commit.CommitInfo; -import org.apache.jackrabbit.oak.spi.commit.EmptyHook; import org.apache.jackrabbit.oak.spi.security.user.UserConstants; -import org.apache.jackrabbit.oak.spi.state.NodeBuilder; -import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.junit.Before; import org.junit.Test; @@ -100,26 +95,11 @@ public class RepositorySidegradeTest { public JackrabbitSession createAdminSession() throws RepositoryException { return (JackrabbitSession) targetRepository.login(CREDENTIALS); } - - // OAK-2869 - private static void setAsync(NodeStore source) throws Exception { - NodeBuilder builder = source.getRoot().builder(); - builder.child(":async").setProperty("test", "123"); - source.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); - } - - // OAK-2869 - @Test - public void verifyAsync() throws Exception { - NodeState state = targetNodeStore.getRoot().getChildNode(":async"); - assertFalse(state.hasProperty("test")); - } @SuppressWarnings("unchecked") protected NodeStore createSourceContent() throws Exception { NodeStore source = SegmentNodeStoreBuilders.builder(new MemoryStore()).build(); - setAsync(source); - + Repository repository = new Jcr(new Oak(source)).createRepository(); Session session = repository.login(CREDENTIALS); diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java index 166fb23..e5f557d 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java @@ -16,11 +16,15 @@ */ package org.apache.jackrabbit.oak.upgrade.cli; +import static java.util.Collections.singletonMap; +import static junit.framework.Assert.assertFalse; import static org.junit.Assert.assertEquals; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; +import java.util.Map; import javax.jcr.Node; import javax.jcr.Property; @@ -29,10 +33,15 @@ import javax.jcr.Session; import javax.jcr.SimpleCredentials; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.commons.IOUtils; import org.apache.jackrabbit.oak.jcr.Jcr; import org.apache.jackrabbit.oak.jcr.repository.RepositoryImpl; import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceIndexProvider; +import org.apache.jackrabbit.oak.spi.commit.CommitInfo; +import org.apache.jackrabbit.oak.spi.commit.EmptyHook; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.apache.jackrabbit.oak.upgrade.RepositorySidegrade; import org.apache.jackrabbit.oak.upgrade.cli.container.NodeStoreContainer; @@ -58,6 +67,8 @@ public abstract class AbstractOak2OakTest { private RepositoryImpl repository; + private String checkpointReference; + protected abstract NodeStoreContainer getSourceContainer(); protected abstract NodeStoreContainer getDestinationContainer(); @@ -103,7 +114,7 @@ public abstract class AbstractOak2OakTest { } } - private void initContent(NodeStore target) throws IOException, RepositoryException { + private void initContent(NodeStore target) throws IOException, RepositoryException, CommitFailedException { NodeStore initialContent = testContent.open(); try { RepositorySidegrade sidegrade = new RepositorySidegrade(initialContent, target); @@ -111,12 +122,26 @@ public abstract class AbstractOak2OakTest { } finally { testContent.close(); } + + NodeBuilder builder = target.getRoot().builder(); + builder.setProperty("checkpoint-state", "before"); + target.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); + checkpointReference = target.checkpoint(60000, singletonMap("key", "123")); + + builder.setProperty("checkpoint-state", "after"); + builder.child(":async").setProperty("test", "123"); + target.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); } @Test public void validateMigration() throws RepositoryException, IOException { verifyContent(session); verifyBlob(session); + if (supportsCheckpointMigration()) { + verifyCheckpoint(); + } else { + verifyEmptyAsync(); + } } static void verifyContent(Session session) throws RepositoryException { @@ -147,4 +172,25 @@ public abstract class AbstractOak2OakTest { } } + private void verifyCheckpoint() { + assertEquals("after", destination.getRoot().getString("checkpoint-state")); + + Map info = destination.checkpointInfo(checkpointReference); + assertEquals("123", info.get("key")); + + NodeState checkpoint = destination.retrieve(checkpointReference); + assertEquals("before", checkpoint.getString("checkpoint-state")); + + assertEquals("123", destination.getRoot().getChildNode(":async").getString("test")); + } + + // OAK-2869 + private void verifyEmptyAsync() { + NodeState state = destination.getRoot().getChildNode(":async"); + assertFalse(state.hasProperty("test")); + } + + protected boolean supportsCheckpointMigration() { + return false; + } } \ No newline at end of file diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentTarToSegmentTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentTarToSegmentTest.java new file mode 100644 index 0000000..f1cb38b --- /dev/null +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentTarToSegmentTest.java @@ -0,0 +1,53 @@ +/* + * 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.upgrade.cli; + +import org.apache.jackrabbit.oak.upgrade.cli.container.NodeStoreContainer; +import org.apache.jackrabbit.oak.upgrade.cli.container.SegmentNodeStoreContainer; +import org.apache.jackrabbit.oak.upgrade.cli.container.SegmentTarNodeStoreContainer; + +public class SegmentTarToSegmentTest extends AbstractOak2OakTest { + + private final NodeStoreContainer source; + + private final NodeStoreContainer destination; + + public SegmentTarToSegmentTest() { + source = new SegmentTarNodeStoreContainer(); + destination = new SegmentNodeStoreContainer(); + } + + @Override + protected NodeStoreContainer getSourceContainer() { + return source; + } + + @Override + protected NodeStoreContainer getDestinationContainer() { + return destination; + } + + @Override + protected String[] getArgs() { + return new String[] { source.getDescription(), destination.getDescription() }; + } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } +} diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTarTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTarTest.java index af8f6dc..2fd5125 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTarTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTarTest.java @@ -45,4 +45,9 @@ public class SegmentToSegmentTarTest extends AbstractOak2OakTest { protected String[] getArgs() { return new String[] { source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTest.java index 3debafb..d5008ca 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTest.java @@ -44,4 +44,9 @@ public class SegmentToSegmentTest extends AbstractOak2OakTest { protected String[] getArgs() { return new String[] { source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyReferencesTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyReferencesTest.java index 395395d..9e07c87 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyReferencesTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyReferencesTest.java @@ -51,4 +51,9 @@ public class CopyReferencesTest extends AbstractOak2OakTest { return new String[] { "--src-datastore", sourceBlob.getDescription(), source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFbsTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFbsTest.java index bde3aef..e29c604 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFbsTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFbsTest.java @@ -54,4 +54,9 @@ public class FbsToFbsTest extends AbstractOak2OakTest { return new String[] { "--copy-binaries", "--src-fileblobstore", sourceBlob.getDescription(), "--fileblobstore", destinationBlob.getDescription(), source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFdsTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFdsTest.java index 9ce3841..39be15c 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFdsTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFdsTest.java @@ -55,4 +55,9 @@ public class FbsToFdsTest extends AbstractOak2OakTest { return new String[] { "--copy-binaries", "--src-fileblobstore", sourceBlob.getDescription(), "--datastore", destinationBlob.getDescription(), source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToS3Test.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToS3Test.java index 1dc50bd..8dc5cf7 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToS3Test.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToS3Test.java @@ -62,4 +62,9 @@ public class FbsToS3Test extends AbstractOak2OakTest { destinationBlob.getDescription(), "--s3config", S3_PROPERTIES, source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FdsToFbsTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FdsToFbsTest.java index 050bf03..de01986 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FdsToFbsTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FdsToFbsTest.java @@ -55,4 +55,9 @@ public class FdsToFbsTest extends AbstractOak2OakTest { return new String[] { "--copy-binaries", "--src-datastore", sourceBlob.getDescription(), "--fileblobstore", destinationBlob.getDescription(), source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } } diff --git a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/S3ToFbsTest.java b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/S3ToFbsTest.java index b79d178..ccfcfb9 100644 --- a/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/S3ToFbsTest.java +++ b/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/S3ToFbsTest.java @@ -62,4 +62,9 @@ public class S3ToFbsTest extends AbstractOak2OakTest { S3_PROPERTIES, "--fileblobstore", destinationBlob.getDescription(), source.getDescription(), destination.getDescription() }; } + + @Override + protected boolean supportsCheckpointMigration() { + return true; + } }