Author: mreutegg
Date: Tue Jan  5 07:47:28 2021
New Revision: 1885133

URL: http://svn.apache.org/viewvc?rev=1885133&view=rev
Log:
OAK-9290: Respect nt:frozenNode definition on upgrade and migration

Added:
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopierTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeState.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopier.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopier.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeStateTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopierTest.java
    
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/InitialContentMigrator.java
    
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
    
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeState.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeState.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeState.java
 Tue Jan  5 07:47:28 2021
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.oak.plugins.migration;
 
 import com.google.common.collect.ImmutableSet;
+
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -24,6 +26,7 @@ import org.jetbrains.annotations.NotNull
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Set;
+
 /**
  * NodeState implementation that decorates another node-state instance
  * in order to hide subtrees or partial subtrees from the consumer of
@@ -47,6 +50,10 @@ import java.util.Set;
  *     <li>{@link #hasChildNode(String)}</li>
  *     <li>{@link #getChildNodeEntries()}</li>
  * </ul>
+ * When <b>referenceableFrozenNodes</b> is set to {@code false}, then the
+ * implementation will hide the {@code jcr:uuid} property on
+ * {@code nt:frozenNode} nodes (see also OAK-9134).
+ * <br>
  * Additionally, hidden node-state names are removed from the property
  * {@code :childOrder} in the following two methods:
  * <ul>
@@ -70,6 +77,8 @@ public class FilteringNodeState extends
 
     private final Set<String> excludedFragments;
 
+    private final boolean referenceableFrozenNodes;
+
     /**
      * Factory method that conditionally decorates the given node-state
      * iff the node-state is (a) hidden itself or (b) has hidden descendants.
@@ -80,6 +89,7 @@ public class FilteringNodeState extends
      * @param excludePaths A Set of paths that should be hidden. Empty if 
{@code null}.
      * @param fragmentPaths A Set of paths that should support the fragments 
(see below). Empty if {@code null}.
      * @param excludedFragments A Set of name fragments that should be hidden. 
Empty if {@code null}.
+     * @param referenceableFrozenNodes Whether nt:frozenNode are referenceable 
on the target.
      * @return The decorated node-state if required, the original node-state 
if decoration is unnecessary.
      */
     @NotNull
@@ -89,39 +99,40 @@ public class FilteringNodeState extends
             @Nullable final Set<String> includePaths,
             @Nullable final Set<String> excludePaths,
             @Nullable final Set<String> fragmentPaths,
-            @Nullable final Set<String> excludedFragments
+            @Nullable final Set<String> excludedFragments,
+            boolean referenceableFrozenNodes
     ) {
         final Set<String> includes = defaultIfEmpty(includePaths, ALL);
         final Set<String> excludes = defaultIfEmpty(excludePaths, NONE);
         final Set<String> safeFragmentPaths = defaultIfEmpty(fragmentPaths, 
NONE);
         final Set<String> safeExcludedFragments = 
defaultIfEmpty(excludedFragments, NONE);
-        if (hasHiddenDescendants(path, includes, excludes, safeFragmentPaths, 
safeExcludedFragments)) {
-            return new FilteringNodeState(path, delegate, includes, excludes, 
fragmentPaths, safeExcludedFragments);
+        if (!referenceableFrozenNodes || hasHiddenDescendants(path, includes, 
excludes, safeFragmentPaths, safeExcludedFragments)) {
+            return new FilteringNodeState(path, delegate, includes, excludes, 
fragmentPaths, safeExcludedFragments, referenceableFrozenNodes);
         }
         return delegate;
     }
 
-    private FilteringNodeState(
-            @NotNull final String path,
-            @NotNull final NodeState delegate,
-            @NotNull final Set<String> includedPaths,
-            @NotNull final Set<String> excludedPaths,
-            @NotNull final Set<String> fragmentPaths,
-            @NotNull final Set<String> excludedFragments
-    ) {
+    private FilteringNodeState(@NotNull final String path,
+                               @NotNull final NodeState delegate,
+                               @NotNull final Set<String> includedPaths,
+                               @NotNull final Set<String> excludedPaths,
+                               @NotNull final Set<String> fragmentPaths,
+                               @NotNull final Set<String> excludedFragments,
+                               boolean referenceableFrozenNodes) {
         super(delegate, false);
         this.path = path;
         this.includedPaths = includedPaths;
         this.excludedPaths = excludedPaths;
         this.fragmentPaths = fragmentPaths;
         this.excludedFragments = excludedFragments;
+        this.referenceableFrozenNodes = referenceableFrozenNodes;
     }
 
     @NotNull
     @Override
     protected NodeState decorateChild(@NotNull final String name, @NotNull 
final NodeState child) {
         final String childPath = PathUtils.concat(path, name);
-        return wrap(childPath, child, includedPaths, excludedPaths, 
fragmentPaths, excludedFragments);
+        return wrap(childPath, child, includedPaths, excludedPaths, 
fragmentPaths, excludedFragments, referenceableFrozenNodes);
     }
 
     @Override
@@ -131,10 +142,34 @@ public class FilteringNodeState extends
 
     @Override
     protected PropertyState decorateProperty(@NotNull final PropertyState 
propertyState) {
+        if (!referenceableFrozenNodes && 
isFrozenNodeUUIDProperty(propertyState)) {
+            return null;
+        }
         return fixChildOrderPropertyState(this, propertyState);
     }
 
     /**
+     * Returns {@code true} if the given property state is the {@code jcr:uuid}
+     * property of a {@code nt:frozenNode}; {@code false} otherwise.
+     *
+     * @param propertyState the property to check.
+     * @return whether the given property state is the {@code jcr:uuid} 
property
+     *          of a {@code nt:frozenNode}.
+     */
+    private boolean isFrozenNodeUUIDProperty(PropertyState propertyState) {
+        return propertyState.getName().equals(JcrConstants.JCR_UUID)
+                && isFrozenNode();
+    }
+
+    /**
+     * @return {@code true} if this node state has a nt:frozenNode;
+     *          {@code false} otherwise.
+     */
+    private boolean isFrozenNode() {
+        return 
JcrConstants.NT_FROZENNODE.equals(delegate.getName(JcrConstants.JCR_PRIMARYTYPE));
+    }
+
+    /**
      * Utility method to determine whether a given path should is hidden given 
the
      * include paths and exclude paths.
      *

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopier.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopier.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopier.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopier.java
 Tue Jan  5 07:47:28 2021
@@ -85,12 +85,20 @@ public class NodeStateCopier {
 
     private final Set<String> mergePaths;
 
-    private NodeStateCopier(Set<String> includePaths, Set<String> 
excludePaths, Set<String> fragmentPaths, Set<String> excludeFragments, 
Set<String> mergePaths) {
+    private final boolean referenceableFrozenNodes;
+
+    private NodeStateCopier(Set<String> includePaths,
+                            Set<String> excludePaths,
+                            Set<String> fragmentPaths,
+                            Set<String> excludeFragments,
+                            Set<String> mergePaths,
+                            boolean referenceableFrozenNodes) {
         this.includePaths = includePaths;
         this.excludePaths = excludePaths;
         this.fragmentPaths = fragmentPaths;
         this.excludeFragments = excludeFragments;
         this.mergePaths = mergePaths;
+        this.referenceableFrozenNodes = referenceableFrozenNodes;
     }
 
     /**
@@ -149,7 +157,7 @@ public class NodeStateCopier {
     }
 
     private boolean copyNodeState(@NotNull final NodeState sourceRoot, 
@NotNull final NodeBuilder targetRoot) {
-        final NodeState wrappedSource = FilteringNodeState.wrap("/", 
sourceRoot, this.includePaths, this.excludePaths, this.fragmentPaths, 
this.excludeFragments);
+        final NodeState wrappedSource = FilteringNodeState.wrap("/", 
sourceRoot, this.includePaths, this.excludePaths, this.fragmentPaths, 
this.excludeFragments, this.referenceableFrozenNodes);
         boolean hasChanges = false;
         for (String includePath : this.includePaths) {
             hasChanges = copyMissingAncestors(sourceRoot, targetRoot, 
includePath) || hasChanges;
@@ -308,6 +316,8 @@ public class NodeStateCopier {
 
         private Set<String> mergePaths = emptySet();
 
+        private boolean referenceableFrozenNodes = true;
+
         private Builder() {}
 
 
@@ -316,7 +326,7 @@ public class NodeStateCopier {
          *
          * @param paths include paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder include(@NotNull Set<String> paths) {
@@ -331,7 +341,7 @@ public class NodeStateCopier {
          *
          * @param paths include paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder include(@NotNull String... paths) {
@@ -343,7 +353,7 @@ public class NodeStateCopier {
          *
          * @param paths exclude paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder exclude(@NotNull Set<String> paths) {
@@ -358,7 +368,7 @@ public class NodeStateCopier {
          *
          * @param paths exclude paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder exclude(@NotNull String... paths) {
@@ -370,7 +380,7 @@ public class NodeStateCopier {
          *
          * @param paths fragment paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder supportFragment(@NotNull Set<String> paths) {
@@ -385,7 +395,7 @@ public class NodeStateCopier {
          *
          * @param paths fragment paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder supportFragment(@NotNull String... paths) {
@@ -397,7 +407,7 @@ public class NodeStateCopier {
          *
          * @param fragments exclude fragments
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder excludeFragments(@NotNull Set<String> fragments) {
@@ -412,7 +422,7 @@ public class NodeStateCopier {
          *
          * @param fragments exclude fragments
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder excludeFragments(@NotNull String... fragments) {
@@ -424,7 +434,7 @@ public class NodeStateCopier {
          *
          * @param paths merge paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder merge(@NotNull Set<String> paths) {
@@ -439,13 +449,19 @@ public class NodeStateCopier {
          *
          * @param paths merge paths
          * @return this Builder instance
-         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set)
+         * @see NodeStateCopier#NodeStateCopier(Set, Set, Set, Set, Set, 
boolean)
          */
         @NotNull
         public Builder merge(@NotNull String... paths) {
             return merge(copyOf(checkNotNull(paths)));
         }
 
+        @NotNull
+        public Builder withReferenceableFrozenNodes(boolean isReferenceable) {
+            this.referenceableFrozenNodes = isReferenceable;
+            return this;
+        }
+
         /**
          * Creates a NodeStateCopier to copy the {@code sourceRoot} NodeState 
to the
          * {@code targetRoot} NodeBuilder, using any include, exclude and 
merge paths
@@ -460,7 +476,7 @@ public class NodeStateCopier {
          *         the same content
          */
         public boolean copy(@NotNull final NodeState sourceRoot, @NotNull 
final NodeBuilder targetRoot) {
-            final NodeStateCopier copier = new NodeStateCopier(includePaths, 
excludePaths, fragmentPaths, excludeFragments, mergePaths);
+            final NodeStateCopier copier = new NodeStateCopier(includePaths, 
excludePaths, fragmentPaths, excludeFragments, mergePaths, 
referenceableFrozenNodes);
             return copier.copyNodeState(checkNotNull(sourceRoot), 
checkNotNull(targetRoot));
         }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopier.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopier.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopier.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopier.java
 Tue Jan  5 07:47:28 2021
@@ -16,14 +16,13 @@
  */
 package org.apache.jackrabbit.oak.plugins.migration.version;
 
-import static org.apache.jackrabbit.JcrConstants.NT_VERSION;
-
 import java.util.Calendar;
 import java.util.Iterator;
+import java.util.function.Supplier;
 
 import org.apache.jackrabbit.oak.plugins.migration.DescendantsIterator;
 import org.apache.jackrabbit.oak.plugins.migration.NodeStateCopier;
-import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
+import org.apache.jackrabbit.oak.plugins.version.Utils;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
@@ -39,19 +38,16 @@ import static org.apache.jackrabbit.oak.
  */
 public class VersionCopier {
 
-    private final TypePredicate isVersion;
-
     private final NodeState sourceVersionStorage;
 
     private final NodeBuilder targetVersionStorage;
 
-    private final NodeBuilder targetRoot;
+    private final Supplier<Boolean> frozenNodeIsReferenceable;
 
     public VersionCopier(NodeBuilder targetRoot, NodeState 
sourceVersionStorage, NodeBuilder targetVersionStorage) {
-        this.isVersion = new TypePredicate(targetRoot.getNodeState(), 
NT_VERSION);
         this.sourceVersionStorage = sourceVersionStorage;
         this.targetVersionStorage = targetVersionStorage;
-        this.targetRoot = targetRoot;
+        this.frozenNodeIsReferenceable = new 
IsFrozenNodeReferenceable(targetRoot.getNodeState());
     }
 
     public static void copyVersionStorage(NodeBuilder targetRoot, NodeState 
sourceVersionStorage, NodeBuilder targetVersionStorage, 
VersionCopyConfiguration config) {
@@ -85,10 +81,29 @@ public class VersionCopier {
             NodeStateCopier.builder()
                     .include(versionHistoryPath)
                     .merge(VERSION_STORE_PATH)
+                    
.withReferenceableFrozenNodes(frozenNodeIsReferenceable.get())
                     .copy(sourceVersionStorage, targetVersionStorage);
             return true;
         }
         return false;
     }
 
+    private static final class IsFrozenNodeReferenceable implements 
Supplier<Boolean> {
+
+        private final NodeState root;
+
+        private Boolean isReferenceable;
+
+        public IsFrozenNodeReferenceable(NodeState root) {
+            this.root = root;
+        }
+
+        @Override
+        public Boolean get() {
+            if (isReferenceable == null) {
+                isReferenceable = Utils.isFrozenNodeReferenceable(root);
+            }
+            return isReferenceable;
+        }
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeStateTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeStateTest.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeStateTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/FilteringNodeStateTest.java
 Tue Jan  5 07:47:28 2021
@@ -18,6 +18,8 @@ package org.apache.jackrabbit.oak.plugin
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
+
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
@@ -30,6 +32,7 @@ import org.junit.Test;
 import javax.jcr.RepositoryException;
 import java.io.IOException;
 import java.util.Set;
+import java.util.UUID;
 
 import static com.google.common.collect.ImmutableSet.of;
 import static com.google.common.collect.Lists.newArrayList;
@@ -72,6 +75,9 @@ public class FilteringNodeStateTest {
         final PropertyState childOrder = createProperty(OAK_CHILD_ORDER, 
asList("foo", "football"), Type.NAMES);
         final NodeBuilder builder = nodeStore.getRoot().builder();
         create(builder, "/content", childOrder);
+        final PropertyState uuid = createProperty(JcrConstants.JCR_UUID, 
UUID.randomUUID().toString(), Type.STRING);
+        final PropertyState ntFrozenNode = 
createProperty(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_FROZENNODE, 
Type.NAME);
+        create(builder, "/" + JcrConstants.JCR_SYSTEM + "/" + 
JcrConstants.JCR_VERSIONSTORAGE + "/dummy/frozen", ntFrozenNode, uuid);
         commit(nodeStore, builder);
 
         rootNodeState = nodeStore.getRoot();
@@ -79,46 +85,46 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldNotDecorateForNullArgs() {
-        final NodeState decorated = wrap("/", rootNodeState, null, null, null, 
null);
+        final NodeState decorated = wrap("/", rootNodeState, null, null, null, 
null, true);
         assertSame("root should be identical to decorated", rootNodeState, 
decorated);
     }
 
     @Test
     public void shouldNotDecorateForDefaultIncludes() {
-        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, 
null, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, 
null, null, null, true);
         assertSame("root should be identical to decorated", rootNodeState, 
decorated);
     }
 
     @Test
     public void shouldNotDecorateForDefaultExcludes() {
-        final NodeState decorated = wrap("/", rootNodeState, null, 
DEFAULT_EXCLUDES, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, 
DEFAULT_EXCLUDES, null, null, true);
         assertSame("root should be identical to decorated", rootNodeState, 
decorated);
     }
 
     @Test
     public void shouldNotDecorateForDefaultIncludesAndExcludes() {
-        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, 
DEFAULT_EXCLUDES, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, DEFAULT_INCLUDES, 
DEFAULT_EXCLUDES, null, null, true);
         assertSame("root should be identical to decorated", rootNodeState, 
decorated);
     }
 
     @Test
     public void shouldNotDecorateIncludedPath() {
         final NodeState content = getNodeState(rootNodeState, "/content");
-        final NodeState decorated = wrap("/content", content, of("/content"), 
null, null, null);
+        final NodeState decorated = wrap("/content", content, of("/content"), 
null, null, null, true);
         assertSame("content should be identical to decorated", content, 
decorated);
     }
 
     @Test
     public void shouldNotDecorateIncludedDescendants() {
         final NodeState foo = getNodeState(rootNodeState, "/content/foo");
-        final NodeState decorated = wrap("/content/foo", foo, of("/content"), 
null, null, null);
+        final NodeState decorated = wrap("/content/foo", foo, of("/content"), 
null, null, null, true);
         assertSame("foo should be identical to decorated", foo, decorated);
     }
 
     @Test
     public void shouldDecorateAncestorOfExcludedDescendants() {
         final NodeState foo = getNodeState(rootNodeState, "/content/foo");
-        final NodeState decorated = wrap("/content/foo", foo, of("/content"), 
of("/content/foo/de"), null, null);
+        final NodeState decorated = wrap("/content/foo", foo, of("/content"), 
of("/content/foo/de"), null, null, true);
         assertNotSame("foo should not be identical to decorated", foo, 
decorated);
 
         assertMissing(decorated, "de");
@@ -134,7 +140,7 @@ public class FilteringNodeStateTest {
     @Test
     public void shouldHaveCorrectChildOrderProperty() throws 
CommitFailedException {
         final NodeState content = rootNodeState.getChildNode("content");
-        final NodeState decorated = wrap("/content", content, null, 
of("/content/foo"), null, null);
+        final NodeState decorated = wrap("/content", content, null, 
of("/content/foo"), null, null, true);
 
         assertTrue(decorated.hasProperty(OAK_CHILD_ORDER));
 
@@ -159,7 +165,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDecorateExcludedNode() {
-        final NodeState decoratedRoot = wrap("/", rootNodeState, 
of("/content"), of("/content/foo/de"), null, null);
+        final NodeState decoratedRoot = wrap("/", rootNodeState, 
of("/content"), of("/content/foo/de"), null, null, true);
         final NodeState de = getNodeState(rootNodeState, "/content/foo/de");
         final NodeState decorated = getNodeState(decoratedRoot, 
"/content/foo/de");
         assertFalse("de should not be equal to decorated", 
de.equals(decorated));
@@ -169,14 +175,14 @@ public class FilteringNodeStateTest {
     @Test
     public void shouldDecorateImplicitlyExcludedNode() {
         final NodeState content = getNodeState(rootNodeState, "/content");
-        final NodeState decorated = wrap("/content", content, of("/apps"), 
null, null, null);
+        final NodeState decorated = wrap("/content", content, of("/apps"), 
null, null, null, true);
         assertNotSame("content should not be identical to decorated", content, 
decorated);
     }
 
 
     @Test
     public void shouldHideExcludedPathsViaExists() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"), null, null, true);
         assertMissing(decorated, "apps");
         assertMissing(decorated, "libs/foo/install");
 
@@ -186,7 +192,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideExcludedPathsViaHasChildNode() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"), null, null, true);
 
         assertExistingHasChildNode(decorated, "content");
         assertMissingHasChildNode(decorated, "apps");
@@ -195,7 +201,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideExcludedPathsViaGetChildNodeNames() {
-        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, of("/apps", 
"/libs"), null, null, true);
 
         assertExistingChildNodeName(decorated, "content");
         assertMissingChildNodeName(decorated, "apps");
@@ -204,7 +210,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideMissingIncludedPathsViaExists() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null, null, null, true);
         assertMissing(decorated, "apps");
         assertMissing(decorated, "libs/foo/install");
 
@@ -214,7 +220,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideMissingIncludedPathsViaHasChildNode() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null, null, null, true);
 
         assertExistingHasChildNode(decorated, "content");
         assertMissingHasChildNode(decorated, "apps");
@@ -223,7 +229,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldHideMissingIncludedPathsViaGetChildNodeNames() {
-        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, of("/content"), 
null, null, null, true);
 
         assertExistingChildNodeName(decorated, "content");
         assertMissingChildNodeName(decorated, "apps");
@@ -232,15 +238,15 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldGivePrecedenceForExcludesOverIncludes() {
-        final NodeState conflictingRules = wrap("/", rootNodeState, 
of("/content"), of("/content"), null, null);
+        final NodeState conflictingRules = wrap("/", rootNodeState, 
of("/content"), of("/content"), null, null, true);
         assertMissingChildNodeName(conflictingRules, "content");
 
-        final NodeState overlappingRules = wrap("/", rootNodeState, 
of("/content"), of("/content/foo"), null, null);
+        final NodeState overlappingRules = wrap("/", rootNodeState, 
of("/content"), of("/content/foo"), null, null, true);
         assertExistingChildNodeName(overlappingRules, "content");
         assertMissingChildNodeName(overlappingRules.getChildNode("content"), 
"foo");
 
 
-        final NodeState overlappingRules2 = wrap("/", rootNodeState, 
of("/content/foo"), of("/content"), null, null);
+        final NodeState overlappingRules2 = wrap("/", rootNodeState, 
of("/content/foo"), of("/content"), null, null, true);
         assertMissingChildNodeName(overlappingRules2, "content");
         assertMissingChildNodeName(overlappingRules2.getChildNode("content"), 
"foo");
 
@@ -248,7 +254,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldRespectPathBoundariesForIncludes() {
-        final NodeState decorated = wrap("/", rootNodeState, 
of("/content/foo"), null, null, null);
+        final NodeState decorated = wrap("/", rootNodeState, 
of("/content/foo"), null, null, null, true);
 
         assertExistingChildNodeName(decorated, "content");
         assertExistingChildNodeName(decorated.getChildNode("content"), "foo");
@@ -257,7 +263,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldRespectPathBoundariesForExcludes() {
-        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null, true);
 
         assertExistingChildNodeName(decorated, "content");
         assertMissingChildNodeName(decorated.getChildNode("content"), "foo");
@@ -266,7 +272,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDelegatePropertyCount() {
-        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo/de"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo/de"), null, null, true);
 
         assertEquals(1, getNodeState(decorated, 
"/content").getPropertyCount());
         assertEquals(0, getNodeState(decorated, 
"/content/foo").getPropertyCount());
@@ -275,7 +281,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDelegateGetProperty() {
-        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null, true);
         final NodeState content = getNodeState(decorated, "/content");
 
         assertNotNull(content.getProperty(OAK_CHILD_ORDER));
@@ -285,7 +291,7 @@ public class FilteringNodeStateTest {
 
     @Test
     public void shouldDelegateHasProperty() {
-        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo/de"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo/de"), null, null, true);
 
         assertTrue(getNodeState(decorated, 
"/content").hasProperty(OAK_CHILD_ORDER));
         assertFalse(getNodeState(decorated, "/content").hasProperty("foo"));
@@ -294,12 +300,25 @@ public class FilteringNodeStateTest {
 
     @Test
     public void exists() {
-        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null);
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null, true);
         assertTrue("/content should exist and be visible", 
getNodeState(decorated, "/content").exists());
         assertFalse("/content/foo should be hidden", getNodeState(decorated, 
"/content/foo").exists());
         assertFalse("/nonexisting should not exist", getNodeState(decorated, 
"/nonexisting").exists());
     }
 
+    @Test
+    public void withoutReferenceableFrozenNode() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null, false);
+        final NodeState frozenNode = getNodeState(decorated, "/" + 
JcrConstants.JCR_SYSTEM + "/" + JcrConstants.JCR_VERSIONSTORAGE + 
"/dummy/frozen");
+        assertNull(frozenNode.getProperty(JcrConstants.JCR_UUID));
+    }
+
+    @Test
+    public void withReferenceableFrozenNode() {
+        final NodeState decorated = wrap("/", rootNodeState, null, 
of("/content/foo"), null, null, true);
+        final NodeState frozenNode = getNodeState(decorated, "/" + 
JcrConstants.JCR_SYSTEM + "/" + JcrConstants.JCR_VERSIONSTORAGE + 
"/dummy/frozen");
+        assertNotNull(frozenNode.getProperty(JcrConstants.JCR_UUID));
+    }
 
     private void assertExistingHasChildNode(NodeState decorated, String name) {
         assertTrue("should have child \"" + name + "\"", 
decorated.hasChildNode(name));

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopierTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopierTest.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopierTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/NodeStateCopierTest.java
 Tue Jan  5 07:47:28 2021
@@ -18,6 +18,7 @@
  */
 package org.apache.jackrabbit.oak.plugins.migration;
 
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
@@ -27,6 +28,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.junit.Test;
 
 import java.io.IOException;
+import java.util.UUID;
 
 import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
 import static 
org.apache.jackrabbit.oak.plugins.migration.NodeStateCopier.builder;
@@ -40,6 +42,9 @@ public class NodeStateCopierTest {
     private final PropertyState primaryType =
             createProperty("jcr:primaryType", "nt:unstructured", Type.NAME);
 
+    private final PropertyState ntFrozenNode =
+            createProperty("jcr:primaryType", "nt:frozenNode", Type.NAME);
+
     @Test
     public void shouldCreateMissingAncestors() throws CommitFailedException, 
IOException {
         final NodeStore source = createPrefilledNodeStore();
@@ -278,4 +283,55 @@ public class NodeStateCopierTest {
                 .verify(before, after);
     }
 
+    @Test
+    public void shouldIgnoreUUIDOfFrozenNode() throws Exception {
+        final NodeStore source = 
createNodeStoreWithContent("/jcr:system/jcr:versionStorage");
+        final NodeStore target = 
createNodeStoreWithContent("/jcr:system/jcr:versionStorage");
+
+        final NodeBuilder builder = source.getRoot().builder();
+        final PropertyState uuid = createProperty(JcrConstants.JCR_UUID, 
UUID.randomUUID().toString());
+        create(builder, "/jcr:system/jcr:versionStorage/frozen", ntFrozenNode, 
uuid);
+        commit(source, builder);
+
+        final NodeState before = target.getRoot();
+        builder()
+                .withReferenceableFrozenNodes(false)
+                .copy(source, target);
+        final NodeState after = target.getRoot();
+
+        expectDifference()
+                .strict()
+                .childNodeChanged("/jcr:system")
+                .childNodeChanged("/jcr:system/jcr:versionStorage")
+                .childNodeAdded("/jcr:system/jcr:versionStorage/frozen")
+                
.propertyAdded("/jcr:system/jcr:versionStorage/frozen/jcr:primaryType")
+                .verify(before, after);
+    }
+
+    @Test
+    public void shouldIncludeUUIDOfFrozenNode() throws Exception {
+        final NodeStore source = 
createNodeStoreWithContent("/jcr:system/jcr:versionStorage");
+        final NodeStore target = 
createNodeStoreWithContent("/jcr:system/jcr:versionStorage");
+
+        final NodeBuilder builder = source.getRoot().builder();
+        final PropertyState uuid = createProperty(JcrConstants.JCR_UUID, 
UUID.randomUUID().toString());
+        create(builder, "/jcr:system/jcr:versionStorage/frozen", ntFrozenNode, 
uuid);
+        commit(source, builder);
+
+        final NodeState before = target.getRoot();
+        builder()
+                .withReferenceableFrozenNodes(true)
+                .copy(source, target);
+        final NodeState after = target.getRoot();
+
+        expectDifference()
+                .strict()
+                .childNodeChanged("/jcr:system")
+                .childNodeChanged("/jcr:system/jcr:versionStorage")
+                .childNodeAdded("/jcr:system/jcr:versionStorage/frozen")
+                
.propertyAdded("/jcr:system/jcr:versionStorage/frozen/jcr:uuid")
+                
.propertyAdded("/jcr:system/jcr:versionStorage/frozen/jcr:primaryType")
+                .verify(before, after);
+    }
+
 }

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopierTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopierTest.java?rev=1885133&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopierTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopierTest.java
 Tue Jan  5 07:47:28 2021
@@ -0,0 +1,167 @@
+/*
+ * 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.migration.version;
+
+import java.util.UUID;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.migration.NodeStateCopier;
+import org.apache.jackrabbit.oak.plugins.version.ReadOnlyVersionManager;
+import org.apache.jackrabbit.oak.plugins.version.ReadWriteVersionManager;
+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.Ignore;
+import org.junit.Test;
+
+import static java.util.Collections.singletonList;
+import static org.apache.jackrabbit.JcrConstants.JCR_FROZENNODE;
+import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
+import static org.apache.jackrabbit.JcrConstants.MIX_VERSIONABLE;
+import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
+import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
+import static 
org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT_FROZEN_NODE_REFERENCEABLE;
+import static 
org.apache.jackrabbit.oak.plugins.migration.NodeStateTestUtils.commit;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class VersionCopierTest {
+
+    @Test
+    public void copyVersionSourceFrozenNodeReferenceable() throws Exception {
+        String path = "/foo";
+        NodeStore source = createVersionFor(path, createStore(true));
+        NodeStore target = createStore(false);
+
+        copyContent(source, target, path);
+        copyVersionStorage(source, target);
+        assertVersionNotReferenceable(target.getRoot(), path);
+    }
+
+    @Test
+    public void copyVersionSourceFrozenNodeNotReferenceable() throws Exception 
{
+        String path = "/foo";
+        NodeStore source = createVersionFor(path, createStore(false));
+        NodeStore target = createStore(false);
+
+        copyContent(source, target, path);
+        copyVersionStorage(source, target);
+        assertVersionNotReferenceable(target.getRoot(), path);
+    }
+
+    @Test
+    public void copyVersionTargetFrozenNodeReferenceable() throws Exception {
+        String path = "/foo";
+        NodeStore source = createVersionFor(path, createStore(true));
+        NodeStore target = createStore(true);
+
+        copyContent(source, target, path);
+        copyVersionStorage(source, target);
+        assertVersionReferenceable(target.getRoot(), path);
+    }
+
+    @Ignore("VersionCopier does not generate referenceable target 
nt:frozenNode from source frozen nodes that are not referenceable")
+    @Test
+    public void copyVersionTargetGenerateReferenceableFrozenNode() throws 
Exception {
+        String path = "/foo";
+        NodeStore source = createVersionFor(path, createStore(false));
+        NodeStore target = createStore(true);
+
+        copyContent(source, target, path);
+        copyVersionStorage(source, target);
+        assertVersionReferenceable(target.getRoot(), path);
+    }
+
+    private void copyContent(NodeStore source, NodeStore target, String path)
+            throws CommitFailedException {
+        NodeStateCopier.builder().include(path).copy(source, target);
+    }
+
+    private void copyVersionStorage(NodeStore source, NodeStore target)
+            throws CommitFailedException {
+        NodeBuilder targetRootBuilder = target.getRoot().builder();
+        VersionCopier.copyVersionStorage(
+                targetRootBuilder,
+                VersionHistoryUtil.getVersionStorage(source.getRoot()),
+                VersionHistoryUtil.getVersionStorage(targetRootBuilder),
+                new VersionCopyConfiguration()
+        );
+        commit(target, targetRootBuilder);
+    }
+
+    private void assertVersionReferenceable(NodeState rootState,
+                                            String versionablePath)
+            throws RepositoryException {
+        assertTrue(getFrozenNode(rootState, 
versionablePath).hasProperty(JCR_UUID));
+    }
+
+    private void assertVersionNotReferenceable(NodeState rootState,
+                                               String versionablePath)
+            throws RepositoryException {
+        assertFalse(getFrozenNode(rootState, 
versionablePath).hasProperty(JCR_UUID));
+    }
+
+    private Tree getFrozenNode(NodeState rootState, String versionablePath)
+            throws RepositoryException {
+        Root root = new ImmutableRoot(rootState);
+        ReadOnlyVersionManager vMgr = ReadOnlyVersionManager.getInstance(
+                root, NamePathMapper.DEFAULT);
+        Tree version = vMgr.getBaseVersion(root.getTree(versionablePath));
+        assertNotNull(version);
+        Tree frozenNode = version.getChild(JCR_FROZENNODE);
+        assertNotNull(frozenNode);
+        return frozenNode;
+    }
+
+    private NodeStore createStore(boolean referenceableFrozenNodes) {
+        NodeState initial = INITIAL_CONTENT;
+        if (referenceableFrozenNodes) {
+            initial = INITIAL_CONTENT_FROZEN_NODE_REFERENCEABLE;
+        }
+        return new MemoryNodeStore(initial);
+    }
+
+    private NodeStore createVersionFor(String path, NodeStore ns) throws 
Exception {
+        NodeBuilder rootBuilder = ns.getRoot().builder();
+        NodeBuilder builder = rootBuilder;
+        for (String name : PathUtils.elements(path)) {
+            builder = builder.child(name);
+        }
+        builder.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, Type.NAME);
+        builder.setProperty(JCR_MIXINTYPES, singletonList(MIX_VERSIONABLE), 
Type.NAMES);
+        builder.setProperty(JCR_UUID, UUID.randomUUID().toString());
+        ReadWriteVersionManager vMgr = new ReadWriteVersionManager(
+                VersionHistoryUtil.getVersionStorage(rootBuilder),
+                rootBuilder
+        );
+        vMgr.checkin(builder);
+        commit(ns, rootBuilder);
+        return ns;
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/migration/version/VersionCopierTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/InitialContentMigrator.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/InitialContentMigrator.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/InitialContentMigrator.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/InitialContentMigrator.java
 Tue Jan  5 07:47:28 2021
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.plugins.migration.FilteringNodeState;
 import org.apache.jackrabbit.oak.plugins.migration.report.LoggingReporter;
 import org.apache.jackrabbit.oak.plugins.migration.report.ReportingNodeState;
+import org.apache.jackrabbit.oak.plugins.version.Utils;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.mount.Mount;
@@ -58,6 +59,8 @@ public class InitialContentMigrator {
 
     private final NodeStore targetNodeStore;
 
+    private final boolean targetHasReferenceableFrozenNode;
+
     private final NodeStore seedNodeStore;
 
     private final Mount seedMount;
@@ -72,6 +75,7 @@ public class InitialContentMigrator {
 
     public InitialContentMigrator(NodeStore targetNodeStore, NodeStore 
seedNodeStore, Mount seedMount) {
         this.targetNodeStore = targetNodeStore;
+        this.targetHasReferenceableFrozenNode = 
Utils.isFrozenNodeReferenceable(targetNodeStore.getRoot());
         this.seedNodeStore = seedNodeStore;
         this.seedMount = seedMount;
 
@@ -208,7 +212,7 @@ public class InitialContentMigrator {
 
     private NodeState wrapNodeState(NodeState nodeState, boolean logPaths) {
         NodeState wrapped = nodeState;
-        wrapped = FilteringNodeState.wrap("/", wrapped, includePaths, 
excludePaths, fragmentPaths, excludeFragments);
+        wrapped = FilteringNodeState.wrap("/", wrapped, includePaths, 
excludePaths, fragmentPaths, excludeFragments, 
targetHasReferenceableFrozenNode);
         if (logPaths) {
             wrapped = ReportingNodeState.wrap(wrapped, new 
LoggingReporter(LOG, "Copying", LOG_NODE_COPY, -1));
         }

Modified: 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
 Tue Jan  5 07:47:28 2021
@@ -40,6 +40,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.migration.report.LoggingReporter;
 import org.apache.jackrabbit.oak.plugins.migration.report.ReportingNodeState;
 import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
+import org.apache.jackrabbit.oak.plugins.version.Utils;
 import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder;
 import org.apache.jackrabbit.oak.segment.SegmentNodeState;
 import org.apache.jackrabbit.oak.segment.file.FileStore;
@@ -100,6 +101,8 @@ public class RepositorySidegrade {
 
     private final FileStore targetFileStore;
 
+    private final boolean targetHasReferenceableFrozenNode;
+
     private final NodeStore source;
 
     /**
@@ -179,6 +182,7 @@ public class RepositorySidegrade {
     public RepositorySidegrade(NodeStore source, NodeStore target) {
         this.source = source;
         this.target = target;
+        this.targetHasReferenceableFrozenNode = 
Utils.isFrozenNodeReferenceable(target.getRoot());
 
         FileStore fs = null;
         if (target instanceof FileStoreUtils.NodeStoreWithFileStore) {
@@ -446,7 +450,7 @@ public class RepositorySidegrade {
 
     private void removeVersions() throws CommitFailedException {
         NodeState root = target.getRoot();
-        NodeState wrappedRoot = FilteringNodeState.wrap(PathUtils.ROOT_PATH, 
root, includePaths, excludePaths, FilteringNodeState.NONE, 
FilteringNodeState.NONE);
+        NodeState wrappedRoot = FilteringNodeState.wrap(PathUtils.ROOT_PATH, 
root, includePaths, excludePaths, FilteringNodeState.NONE, 
FilteringNodeState.NONE, targetHasReferenceableFrozenNode);
         NodeState versionStorage = getVersionStorage(root);
         List<String> versionablesToStrip = 
VersionHistoryUtil.getVersionableNodes(wrappedRoot, versionStorage, new 
TypePredicate(root, JcrConstants.MIX_VERSIONABLE), 
versionCopyConfiguration.getVersionsMinDate());
         if (!versionablesToStrip.isEmpty()) {
@@ -536,7 +540,7 @@ public class RepositorySidegrade {
             wrapped = MetadataExposingNodeState.wrap(wrapped);
         }
         if (!isCompleteMigration() && filterPaths) {
-            wrapped = FilteringNodeState.wrap("/", wrapped, includePaths, 
excludePaths, FilteringNodeState.NONE, FilteringNodeState.NONE);
+            wrapped = FilteringNodeState.wrap("/", wrapped, includePaths, 
excludePaths, FilteringNodeState.NONE, FilteringNodeState.NONE, 
targetHasReferenceableFrozenNode);
         }
         if (tracePaths) {
             wrapped = ReportingNodeState.wrap(wrapped, new 
LoggingReporter(LOG, "Copying", LOG_NODE_COPY, -1));

Modified: 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1885133&r1=1885132&r2=1885133&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
 Tue Jan  5 07:47:28 2021
@@ -564,7 +564,8 @@ public class RepositoryUpgrade {
 
     private void removeVersions() throws CommitFailedException {
         NodeState root = target.getRoot();
-        NodeState wrappedRoot = FilteringNodeState.wrap(PathUtils.ROOT_PATH, 
root, includePaths, excludePaths, FilteringNodeState.NONE, 
FilteringNodeState.NONE);
+        boolean frozenNodeReferenceable = 
org.apache.jackrabbit.oak.plugins.version.Utils.isFrozenNodeReferenceable(root);
+        NodeState wrappedRoot = FilteringNodeState.wrap(PathUtils.ROOT_PATH, 
root, includePaths, excludePaths, FilteringNodeState.NONE, 
FilteringNodeState.NONE, frozenNodeReferenceable);
         NodeState versionStorage = getVersionStorage(root);
         List<String> versionablesToStrip = 
VersionHistoryUtil.getVersionableNodes(wrappedRoot, versionStorage, new 
TypePredicate(root, JcrConstants.MIX_VERSIONABLE), 
versionCopyConfiguration.getVersionsMinDate());
         if (!versionablesToStrip.isEmpty()) {


Reply via email to