Author: tomekr
Date: Fri Dec 16 11:12:53 2016
New Revision: 1774571

URL: http://svn.apache.org/viewvc?rev=1774571&view=rev
Log:
OAK-5290 Backported the oak-upgrade from trunk.

Added:
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/core/
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/core/IndexAccessor.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/LoggingEqualsDiff.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/ConstantBlobStoreFactory.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStore.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStoreFactory.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/DatastoreArguments.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/security/AuthorizableFolderEditor.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AuthorizableFolderEditorTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/UpgradeOldSegmentTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/MongoToMongoFdsTest.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/MongoToMongoFds.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentWithMissingDestinationDirectoryTest.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyReferencesTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyBinariesTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/parser/
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreArgumentsTest.java
      - copied, changed from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
    jackrabbit/oak/branches/1.4/oak-upgrade/src/test/resources/test-repo-1.0.zip
Removed:
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/MongoToMongoFds.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/CopyReferencesTest.java
Modified:
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/blob/LengthCachingDataStore.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/CliUtils.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/OakUpgrade.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/JdbcFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/MongoFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/SegmentFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/StoreFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationCliArguments.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreArguments.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/StoreType.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/FilteringNodeState.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/NameFilteringNodeState.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/nodestate/report/ReportingNodeState.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopier.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionCopyConfiguration.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionHistoryUtil.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionableEditor.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/version/VersionablePropertiesEditor.java
    jackrabbit/oak/branches/1.4/oak-upgrade/src/main/resources/upgrade_usage.txt
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/AbstractRepositoryUpgradeTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/BrokenVersionableTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/CopyVersionHistoryTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/LongNameTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepeatedRepositorySidegradeTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegradeTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/SameNodeSiblingsTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/blob/LengthCachingDataStoreTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/Jcr2ToSegmentTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToJdbcTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/SegmentToSegmentTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFbsTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToFdsTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FbsToS3Test.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/FdsToFbsTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/blob/S3ToFbsTest.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/container/FileBlobStoreContainer.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/container/FileDataStoreContainer.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/container/JdbcNodeStoreContainer.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/container/MongoNodeStoreContainer.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/container/S3DataStoreContainer.java
    
jackrabbit/oak/branches/1.4/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/container/SegmentNodeStoreContainer.java

Copied: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/core/IndexAccessor.java
 (from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java)
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/core/IndexAccessor.java?p2=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/core/IndexAccessor.java&p1=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java&r1=1774499&r2=1774571&rev=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/core/IndexAccessor.java
 Fri Dec 16 11:12:53 2016
@@ -14,16 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.oak.upgrade.cli.node;
+package org.apache.jackrabbit.core;
 
+import org.apache.jackrabbit.core.query.QueryHandler;
+import org.apache.jackrabbit.core.query.lucene.SearchIndex;
+import org.apache.lucene.index.IndexReader;
+
+import javax.jcr.RepositoryException;
 import java.io.IOException;
 
-import org.apache.jackrabbit.oak.spi.blob.BlobStore;
-import org.apache.jackrabbit.oak.spi.state.NodeStore;
+public final class IndexAccessor {
 
-import com.google.common.io.Closer;
+    private IndexAccessor() {
+    }
 
-public interface NodeStoreFactory {
+    public static IndexReader getReader(RepositoryContext ctx) throws 
RepositoryException, IOException {
+        RepositoryImpl repo = ctx.getRepository();
+        SearchManager searchMgr = 
repo.getSearchManager(ctx.getRepositoryConfig().getDefaultWorkspaceName());
+        if (searchMgr == null) {
+            return null;
+        }
+        QueryHandler handler = searchMgr.getQueryHandler();
+        SearchIndex index = (SearchIndex) handler;
+        return index.getIndexReader();
+    }
 
-    NodeStore create(BlobStore blobStore, Closer closer) throws IOException;
 }

Added: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/LoggingEqualsDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/LoggingEqualsDiff.java?rev=1774571&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/LoggingEqualsDiff.java
 (added)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/LoggingEqualsDiff.java
 Fri Dec 16 11:12:53 2016
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.slf4j.Logger;
+
+public class LoggingEqualsDiff implements NodeStateDiff {
+
+    private final Logger log;
+
+    private final String path;
+
+    private boolean pathDisplayed;
+
+    public LoggingEqualsDiff(Logger log, String path) {
+        this.log = log;
+        this.path = path;
+    }
+
+    @Override
+    public boolean propertyAdded(PropertyState after) {
+        displayPath();
+        log.info("  + {}<{}>", after.getName(), after.getType());
+        return false;
+    }
+
+    @Override
+    public boolean propertyChanged(PropertyState before, PropertyState after) {
+        displayPath();
+        log.info("  ^ {}<{}>", before.getName(), before.getType());
+        return false;
+    }
+
+    @Override
+    public boolean propertyDeleted(PropertyState before) {
+        displayPath();
+        log.info("  - {}<{}>", before.getName(), before.getType());
+        return false;
+    }
+
+    @Override
+    public boolean childNodeAdded(String name, NodeState after) {
+        String childPath = PathUtils.concat(path, name);
+        log.info("+ {}", childPath);
+        return false;
+    }
+
+    @Override
+    public boolean childNodeChanged(String name, NodeState before, NodeState 
after) {
+        String childPath = PathUtils.concat(path, name);
+        return after.compareAgainstBaseState(before, new 
LoggingEqualsDiff(log, childPath));
+    }
+
+    @Override
+    public boolean childNodeDeleted(String name, NodeState before) {
+        String childPath = PathUtils.concat(path, name);
+        log.info("- {}", childPath);
+        return false;
+    }
+
+    private void displayPath() {
+        if (!pathDisplayed) {
+            log.info("^ {}", path);
+            pathDisplayed = true;
+        }
+    }
+}

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositorySidegrade.java
 Fri Dec 16 11:12:53 2016
@@ -18,29 +18,35 @@ package org.apache.jackrabbit.oak.upgrad
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.jcr.RepositoryException;
 
-import org.apache.jackrabbit.oak.Oak;
+import com.google.common.base.Function;
+import org.apache.commons.lang.StringUtils;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.state.ApplyDiff;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 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.RepositoryUpgrade.LoggingCompositeHook;
+import org.apache.jackrabbit.oak.upgrade.cli.node.TarNodeStore;
 import org.apache.jackrabbit.oak.upgrade.nodestate.NameFilteringNodeState;
 import org.apache.jackrabbit.oak.upgrade.nodestate.report.LoggingReporter;
 import org.apache.jackrabbit.oak.upgrade.nodestate.report.ReportingNodeState;
 import org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier;
 import org.apache.jackrabbit.oak.upgrade.version.VersionCopyConfiguration;
+import org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil;
 import org.apache.jackrabbit.oak.upgrade.version.VersionableEditor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,7 +54,14 @@ import org.slf4j.LoggerFactory;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.ImmutableSet.copyOf;
 import static com.google.common.collect.ImmutableSet.of;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Lists.transform;
 import static com.google.common.collect.Sets.union;
+import static java.util.Collections.sort;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants.NT_REP_PERMISSION_STORE;
+import static 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants.REP_PERMISSION_STORE;
 import static 
org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_EXCLUDE_PATHS;
 import static 
org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_INCLUDE_PATHS;
 import static 
org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.DEFAULT_MERGE_PATHS;
@@ -58,11 +71,16 @@ import static org.apache.jackrabbit.oak.
 import static 
org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade.markIndexesToBeRebuilt;
 import static 
org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier.copyProperties;
 import static 
org.apache.jackrabbit.oak.upgrade.version.VersionCopier.copyVersionStorage;
+import static 
org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionStorage;
 
 public class RepositorySidegrade {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(RepositorySidegrade.class);
 
+    private static final int LOG_NODE_COPY = 
Integer.getInteger("oak.upgrade.logNodeCopy", 10000);
+
+    private static final String WORKSPACE_NAME_PROP = 
"oak.upgrade.workspaceName";
+
     /**
      * Target node store.
      */
@@ -85,9 +103,11 @@ public class RepositorySidegrade {
      */
     private Set<String> mergePaths = DEFAULT_MERGE_PATHS;
 
-    private boolean skipLongNames = true;
+    private boolean filterLongNames = true;
+
+    private boolean verify = false;
 
-    private boolean skipInitialization = false;
+    private boolean onlyVerify = false;
 
     private List<CommitHook> customCommitHooks = null;
 
@@ -112,8 +132,8 @@ public class RepositorySidegrade {
      * not referenced by the existing nodes). By default all orphaned version
      * histories are copied. One may disable it completely by setting
      * {@code null} here or limit it to a selected date range:
-     * {@code <minDate, now()>}. <br/>
-     * <br/>
+     * {@code <minDate, now()>}. <br>
+     * <br>
      * Please notice, that this option is overriden by the
      * {@link #setCopyVersions(Calendar)}. You can't copy orphaned versions
      * older than set in {@link #setCopyVersions(Calendar)} and if you set
@@ -181,7 +201,6 @@ public class RepositorySidegrade {
         this.excludePaths = copyOf(checkNotNull(excludes));
     }
 
-
     /**
      * Sets the paths that should be merged when the source repository
      * is copied to the target repository.
@@ -192,22 +211,20 @@ public class RepositorySidegrade {
         this.mergePaths = copyOf(checkNotNull(merges));
     }
 
-    public boolean isSkipLongNames() {
-        return skipLongNames;
+    public boolean isFilterLongNames() {
+        return filterLongNames;
     }
 
-    public void setSkipLongNames(boolean skipLongNames) {
-        this.skipLongNames = skipLongNames;
+    public void setFilterLongNames(boolean filterLongNames) {
+        this.filterLongNames = filterLongNames;
     }
 
-    /**
-     * Skip the new repository initialization. Only copy content passed in the
-     * {@link #includePaths}.
-     *
-     * @param skipInitialization
-     */
-    public void setSkipInitialization(boolean skipInitialization) {
-        this.skipInitialization = skipInitialization;
+    public void setVerify(boolean verify) {
+        this.verify = verify;
+    }
+
+    public void setOnlyVerify(boolean onlyVerify) {
+        this.onlyVerify = onlyVerify;
     }
 
     /**
@@ -227,31 +244,35 @@ public class RepositorySidegrade {
      * during the copy operation as this method requires exclusive access
      * to the repositories.
      * 
-     * @param initializer optional extra repository initializer to use
+     * @param initializer optional repository initializer to use
      *
      * @throws RepositoryException if the copy operation fails
      */
     public void copy(RepositoryInitializer initializer) throws 
RepositoryException {
         try {
-            NodeBuilder targetRoot = target.getRoot().builder();
+            if (!onlyVerify) {
+                NodeBuilder targetRoot = target.getRoot().builder();
+                if (VersionHistoryUtil.getVersionStorage(targetRoot).exists() 
&& !versionCopyConfiguration.skipOrphanedVersionsCopy()) {
+                    LOG.warn("The version storage on destination already 
exists. Orphaned version histories will be skipped.");
+                    versionCopyConfiguration.setCopyOrphanedVersions(null);
+                }
 
-            if (skipInitialization) {
-                LOG.info("Skipping the repository initialization");
-            } else {
-                new InitialContent().initialize(targetRoot);
                 if (initializer != null) {
                     initializer.initialize(targetRoot);
                 }
-            }
 
-            final NodeState reportingSourceRoot = 
ReportingNodeState.wrap(source.getRoot(), new LoggingReporter(LOG, "Copying", 
10000, -1));
-            final NodeState sourceRoot;
-            if (skipLongNames) {
-                sourceRoot = NameFilteringNodeState.wrap(reportingSourceRoot);
-            } else {
-                sourceRoot = reportingSourceRoot;
+                final NodeState reportingSourceRoot = 
ReportingNodeState.wrap(source.getRoot(), new LoggingReporter(LOG, "Copying", 
LOG_NODE_COPY, -1));
+                final NodeState sourceRoot;
+                if (filterLongNames) {
+                    sourceRoot = 
NameFilteringNodeState.wrap(reportingSourceRoot);
+                } else {
+                    sourceRoot = reportingSourceRoot;
+                }
+                copyState(sourceRoot, targetRoot);
+            }
+            if (verify || onlyVerify) {
+                verify();
             }
-            copyState(sourceRoot, targetRoot);
 
         } catch (Exception e) {
             throw new RepositoryException("Failed to copy content", e);
@@ -259,29 +280,48 @@ public class RepositorySidegrade {
     }
 
     private void removeCheckpointReferences(NodeBuilder builder) throws 
CommitFailedException {
-        // removing references to the checkpoints, 
+        // removing references to the checkpoints,
         // which don't exist in the new repository
         builder.setChildNode(":async");
     }
 
-    private void copyState(NodeState sourceRoot, NodeBuilder targetRoot) 
throws CommitFailedException {
+    private void copyState(NodeState sourceRoot, NodeBuilder targetRoot) 
throws CommitFailedException, RepositoryException {
         copyWorkspace(sourceRoot, targetRoot);
-        removeCheckpointReferences(targetRoot);
-        if (!versionCopyConfiguration.skipOrphanedVersionsCopy()) {
-            copyVersionStorage(sourceRoot, targetRoot, 
versionCopyConfiguration);
+
+        boolean isRemoveCheckpointReferences = false;
+        if (!isCompleteMigration()) {
+            LOG.info("Custom paths have been specified, checkpoints won't be 
migrated");
+            isRemoveCheckpointReferences = true;
+        } else {
+            boolean checkpointsCopied = copyCheckpoints(targetRoot);
+            if (!checkpointsCopied) {
+                LOG.info("Copying checkpoints is not supported for this 
combination of node stores");
+                isRemoveCheckpointReferences = true;
+            }
+        }
+        if (isRemoveCheckpointReferences) {
+            removeCheckpointReferences(targetRoot);
         }
 
         final List<CommitHook> hooks = new ArrayList<CommitHook>();
-        hooks.add(new EditorHook(
-                new VersionableEditor.Provider(sourceRoot, 
Oak.DEFAULT_WORKSPACE_NAME, versionCopyConfiguration)));
+        if (!versionCopyConfiguration.isCopyAll()) {
+            NodeBuilder versionStorage = 
VersionHistoryUtil.getVersionStorage(targetRoot);
+            if (!versionStorage.exists()) { // it's possible that this is a 
new repository and the version storage
+                                            // hasn't been created/copied yet
+                versionStorage = 
VersionHistoryUtil.createVersionStorage(targetRoot);
+            }
+            if (!versionCopyConfiguration.skipOrphanedVersionsCopy()) {
+                copyVersionStorage(targetRoot, getVersionStorage(sourceRoot), 
versionStorage, versionCopyConfiguration);
+            }
+            hooks.add(new EditorHook(new 
VersionableEditor.Provider(sourceRoot, getWorkspaceName(), 
versionCopyConfiguration)));
+        }
 
         if (customCommitHooks != null) {
             hooks.addAll(customCommitHooks);
         }
 
-        markIndexesToBeRebuilt(targetRoot);
-
         if (!isCompleteMigration()) {
+            markIndexesToBeRebuilt(targetRoot);
             // type validation, reference and indexing hooks
             hooks.add(new EditorHook(new CompositeEditorProvider(
                     createTypeEditorProvider(),
@@ -298,7 +338,12 @@ public class RepositorySidegrade {
 
     private void copyWorkspace(NodeState sourceRoot, NodeBuilder targetRoot) {
         final Set<String> includes = 
calculateEffectiveIncludePaths(includePaths, sourceRoot);
-        final Set<String> excludes = union(copyOf(this.excludePaths), 
of("/jcr:system/jcr:versionStorage"));
+        final Set<String> excludes;
+        if (versionCopyConfiguration.isCopyAll()) {
+            excludes = copyOf(this.excludePaths);
+        } else {
+            excludes = union(copyOf(this.excludePaths), 
of("/jcr:system/jcr:versionStorage"));
+        }
         final Set<String> merges = union(copyOf(this.mergePaths), 
of("/jcr:system"));
 
         NodeStateCopier.builder()
@@ -311,4 +356,138 @@ public class RepositorySidegrade {
             copyProperties(sourceRoot, targetRoot);
         }
     }
-}
\ No newline at end of file
+
+    private boolean copyCheckpoints(NodeBuilder targetRoot) {
+        if (!(source instanceof TarNodeStore && target instanceof 
TarNodeStore)) {
+            return false;
+        }
+
+        TarNodeStore sourceTarNS = (TarNodeStore) source;
+        TarNodeStore targetTarNS = (TarNodeStore) target;
+
+        NodeState sourceSuperRoot = sourceTarNS.getSuperRoot();
+        NodeBuilder targetSuperRoot = targetTarNS.getSuperRoot().builder();
+
+        String previousCheckpoint = null;
+        for (String checkpoint : getCheckpointNames(sourceSuperRoot)) {
+            NodeState targetPreviousRoot, sourcePreviousRoot;
+            if (previousCheckpoint == null) {
+                sourcePreviousRoot = source.getRoot();
+                targetPreviousRoot = targetRoot.getNodeState();
+            } else {
+                sourcePreviousRoot = getCheckpointRoot(sourceSuperRoot, 
previousCheckpoint);
+                targetPreviousRoot = 
getCheckpointRoot(targetSuperRoot.getNodeState(), previousCheckpoint);
+            }
+            NodeState sourceCheckpoint = getCheckpoint(sourceSuperRoot, 
checkpoint);
+            NodeBuilder targetCheckpoint = getCheckpoint(targetSuperRoot, 
checkpoint);
+
+            // copy checkpoint metadata
+            NodeStateCopier.copyProperties(sourceCheckpoint, targetCheckpoint);
+            targetCheckpoint.setChildNode("properties", 
sourceCheckpoint.getChildNode("properties"));
+
+            // create the checkpoint root
+            NodeState sourceCheckpointRoot = 
sourceCheckpoint.getChildNode("root");
+            NodeBuilder targetCheckpointRoot = 
targetCheckpoint.setChildNode("root", targetPreviousRoot);
+            sourceCheckpointRoot.compareAgainstBaseState(sourcePreviousRoot, 
new ApplyDiff(targetCheckpointRoot));
+
+            previousCheckpoint = checkpoint;
+        }
+
+        targetTarNS.setSuperRoot(targetSuperRoot);
+        return true;
+   }
+
+    /**
+     * Return all checkpoint paths, sorted by their "created" property, 
descending.
+     *
+     * @param superRoot
+     * @return
+     */
+    private static List<String> getCheckpointNames(NodeState superRoot) {
+        List<ChildNodeEntry> checkpoints = 
newArrayList(superRoot.getChildNode("checkpoints").getChildNodeEntries().iterator());
+        sort(checkpoints, new Comparator<ChildNodeEntry>() {
+            @Override
+            public int compare(ChildNodeEntry o1, ChildNodeEntry o2) {
+                long c1 = o1.getNodeState().getLong("created");
+                long c2 = o1.getNodeState().getLong("created");
+                return -Long.compare(c1, c2);
+            }
+        });
+        return transform(checkpoints, new Function<ChildNodeEntry, String>() {
+            @Nullable
+            @Override
+            public String apply(@Nullable ChildNodeEntry input) {
+                return input.getName();
+            }
+        });
+    }
+
+    private static NodeState getCheckpointRoot(NodeState superRoot, String 
name) {
+        return getCheckpoint(superRoot, name).getChildNode("root");
+    }
+
+    private static NodeState getCheckpoint(NodeState superRoot, String name) {
+        return superRoot.getChildNode("checkpoints").getChildNode(name);
+    }
+
+    private static NodeBuilder getCheckpoint(NodeBuilder superRoot, String 
name) {
+        return superRoot.child("checkpoints").child(name);
+    }
+
+    private String getWorkspaceName() throws RepositoryException {
+        String definedName = System.getProperty(WORKSPACE_NAME_PROP);
+        String detectedName = deriveWorkspaceName();
+        if (StringUtils.isNotBlank(definedName)) {
+            return definedName;
+        } else if (StringUtils.isNotBlank(detectedName)) {
+            return detectedName;
+        } else {
+            throw new RepositoryException("Can't detect the workspace name. 
Please use the system property " + WORKSPACE_NAME_PROP + " to set it 
manually.");
+        }
+    }
+
+    /**
+     * This method tries to derive the workspace name from the source 
repository. It uses the
+     * fact that the /jcr:system/rep:permissionStore usually contains just one 
child
+     * named after the workspace.
+     *
+     * @return the workspace name or null if it can't be derived
+     */
+    private String deriveWorkspaceName() {
+        NodeState permissionStore = 
source.getRoot().getChildNode(JCR_SYSTEM).getChildNode(REP_PERMISSION_STORE);
+        List<String> nameCandidates = new ArrayList<String>();
+        for (ChildNodeEntry e : permissionStore.getChildNodeEntries()) {
+            String primaryType = e.getNodeState().getName(JCR_PRIMARYTYPE);
+            if (NT_REP_PERMISSION_STORE.equals(primaryType)) {
+                nameCandidates.add(e.getName());
+            }
+        }
+        if (nameCandidates.size() == 1) {
+            return nameCandidates.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    private void verify() {
+        final NodeState sourceRoot;
+        final NodeState targetRoot;
+
+        if (source instanceof TarNodeStore && target instanceof TarNodeStore) {
+            sourceRoot = ((TarNodeStore) source).getSuperRoot();
+            targetRoot = ((TarNodeStore) target).getSuperRoot();
+        } else {
+            sourceRoot = source.getRoot();
+            targetRoot = target.getRoot();
+        }
+
+        final NodeState reportingSource = ReportingNodeState.wrap(sourceRoot, 
new LoggingReporter(LOG, "Verifying", LOG_NODE_COPY, -1));
+
+        LOG.info("Verifying whether repositories are identical");
+        if (targetRoot.compareAgainstBaseState(reportingSource, new 
LoggingEqualsDiff(LOG, "/"))) {
+            LOG.info("Verification result: both repositories are identical");
+        } else {
+            LOG.warn("Verification result: repositories are not identical");
+        }
+    }
+}

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
 Fri Dec 16 11:12:53 2016
@@ -31,6 +31,7 @@ import static org.apache.jackrabbit.oak.
 import static 
org.apache.jackrabbit.oak.plugins.name.Namespaces.addCustomMapping;
 import static 
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NODE_TYPES_PATH;
 import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_ALL;
+import static 
org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory.SKIP_NAME_CHECK;
 import static 
org.apache.jackrabbit.oak.upgrade.nodestate.FilteringNodeState.ALL;
 import static 
org.apache.jackrabbit.oak.upgrade.nodestate.FilteringNodeState.NONE;
 import static 
org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier.copyProperties;
@@ -51,7 +52,9 @@ import java.util.concurrent.TimeUnit;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.jcr.NamespaceException;
+import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.nodetype.NodeDefinitionTemplate;
@@ -68,6 +71,7 @@ import com.google.common.collect.Immutab
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.core.IndexAccessor;
 import org.apache.jackrabbit.core.RepositoryContext;
 import org.apache.jackrabbit.core.config.BeanConfig;
 import org.apache.jackrabbit.core.config.LoginModuleConfig;
@@ -76,6 +80,7 @@ import org.apache.jackrabbit.core.config
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.query.lucene.FieldNames;
 import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
 import org.apache.jackrabbit.core.security.user.UserManagerImpl;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
@@ -89,7 +94,6 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdate;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
 import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
-import 
org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditorProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import 
org.apache.jackrabbit.oak.plugins.index.reference.ReferenceEditorProvider;
 import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants;
@@ -121,9 +125,11 @@ import org.apache.jackrabbit.oak.upgrade
 import org.apache.jackrabbit.oak.upgrade.nodestate.report.LoggingReporter;
 import org.apache.jackrabbit.oak.upgrade.nodestate.report.ReportingNodeState;
 import org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier;
+import org.apache.jackrabbit.oak.upgrade.security.AuthorizableFolderEditor;
 import org.apache.jackrabbit.oak.upgrade.security.GroupEditorProvider;
 import org.apache.jackrabbit.oak.upgrade.security.RestrictionEditorProvider;
 import org.apache.jackrabbit.oak.upgrade.version.VersionCopyConfiguration;
+import org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil;
 import org.apache.jackrabbit.oak.upgrade.version.VersionableEditor;
 import org.apache.jackrabbit.oak.upgrade.version.VersionablePropertiesEditor;
 import org.apache.jackrabbit.spi.Name;
@@ -135,16 +141,23 @@ import org.apache.jackrabbit.spi.QValueC
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.apache.jackrabbit.spi.commons.value.ValueFormat;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.TermEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static 
org.apache.jackrabbit.oak.upgrade.version.VersionCopier.copyVersionStorage;
+import static 
org.apache.jackrabbit.oak.upgrade.version.VersionHistoryUtil.getVersionStorage;
 
 public class RepositoryUpgrade {
 
     private static final Logger logger = 
LoggerFactory.getLogger(RepositoryUpgrade.class);
 
-    private static final Set<String> INDEXES_TO_REBUILD = 
ImmutableSet.of("counter");
+    private static final int LOG_NODE_COPY = 
Integer.getInteger("oak.upgrade.logNodeCopy", 10000);
+
+    private static final Set<String> INDEXES_TO_REBUILD = 
ImmutableSet.of("counter", "uuid");
 
     public static final Set<String> DEFAULT_INCLUDE_PATHS = ALL;
 
@@ -188,7 +201,9 @@ public class RepositoryUpgrade {
 
     private List<CommitHook> customCommitHooks = null;
 
-    private boolean skipLongNames = true;
+    private boolean checkLongNames = false;
+
+    private boolean filterLongNames = true;
 
     private boolean skipInitialization = false;
 
@@ -262,12 +277,20 @@ public class RepositoryUpgrade {
         this.earlyShutdown = earlyShutdown;
     }
 
-    public boolean isSkipLongNames() {
-        return skipLongNames;
+    public boolean isCheckLongNames() {
+        return checkLongNames;
+    }
+
+    public void setCheckLongNames(boolean checkLongNames) {
+        this.checkLongNames = checkLongNames;
+    }
+
+    public boolean isFilterLongNames() {
+        return filterLongNames;
     }
 
-    public void setSkipLongNames(boolean skipLongNames) {
-        this.skipLongNames = skipLongNames;
+    public void setFilterLongNames(boolean filterLongNames) {
+        this.filterLongNames = filterLongNames;
     }
 
     public boolean isSkipInitialization() {
@@ -318,7 +341,6 @@ public class RepositoryUpgrade {
         this.excludePaths = copyOf(checkNotNull(excludes));
     }
 
-
     /**
      * Sets the paths that should be merged when the source repository
      * is copied to the target repository.
@@ -348,8 +370,8 @@ public class RepositoryUpgrade {
      * not referenced by the existing nodes). By default all orphaned version
      * histories are copied. One may disable it completely by setting
      * {@code null} here or limit it to a selected date range:
-     * {@code <minDate, now()>}. <br/>
-     * <br/>
+     * {@code <minDate, now()>}. <br>
+     * <br>
      * Please notice, that this option is overriden by the
      * {@link #setCopyVersions(Calendar)}. You can't copy orphaned versions
      * older than set in {@link #setCopyVersions(Calendar)} and if you set
@@ -378,10 +400,18 @@ public class RepositoryUpgrade {
      * @throws RepositoryException if the copy operation fails
      */
     public void copy(RepositoryInitializer initializer) throws 
RepositoryException {
+        if (checkLongNames) {
+            assertNoLongNames();
+        }
+
         RepositoryConfig config = source.getRepositoryConfig();
         logger.info("Copying repository content from {} to Oak", 
config.getHomeDir());
         try {
             NodeBuilder targetBuilder = target.getRoot().builder();
+            if (VersionHistoryUtil.getVersionStorage(targetBuilder).exists() 
&& !versionCopyConfiguration.skipOrphanedVersionsCopy()) {
+                logger.warn("The version storage on destination already 
exists. Orphaned version histories will be skipped.");
+                versionCopyConfiguration.setCopyOrphanedVersions(null);
+            }
             final Root upgradeRoot = new UpgradeRoot(targetBuilder);
 
             String workspaceName =
@@ -453,10 +483,10 @@ public class RepositoryUpgrade {
                             source, workspaceName, 
targetBuilder.getNodeState(), 
                             uriToPrefix, copyBinariesByReference, skipOnError
                     ),
-                    new LoggingReporter(logger, "Migrating", 10000, -1)
+                    new LoggingReporter(logger, "Migrating", LOG_NODE_COPY, -1)
             );
             final NodeState sourceRoot;
-            if (skipLongNames) {
+            if (filterLongNames) {
                 sourceRoot = NameFilteringNodeState.wrap(reportingSourceRoot);
             } else {
                 sourceRoot = reportingSourceRoot;
@@ -472,7 +502,7 @@ public class RepositoryUpgrade {
             if (!versionCopyConfiguration.skipOrphanedVersionsCopy()) {
                 logger.info("Copying version storage");
                 watch.reset().start();
-                copyVersionStorage(sourceRoot, targetBuilder, 
versionCopyConfiguration);
+                copyVersionStorage(targetBuilder, 
getVersionStorage(sourceRoot), getVersionStorage(targetBuilder), 
versionCopyConfiguration);
                 targetBuilder.getNodeState(); // on TarMK this does call 
triggers the actual copy
                 logger.info("Version storage copied in {}s ({})", 
watch.elapsed(TimeUnit.SECONDS), watch);
             } else {
@@ -489,6 +519,9 @@ public class RepositoryUpgrade {
             String groupsPath = userConf.getParameters().getConfigValue(
                     UserConstants.PARAM_GROUP_PATH,
                     UserConstants.DEFAULT_GROUP_PATH);
+            String usersPath = userConf.getParameters().getConfigValue(
+                    UserConstants.PARAM_USER_PATH,
+                    UserConstants.DEFAULT_USER_PATH);
 
             // hooks specific to the upgrade, need to run first
             hooks.add(new EditorHook(new CompositeEditorProvider(
@@ -496,7 +529,8 @@ public class RepositoryUpgrade {
                     new GroupEditorProvider(groupsPath),
                     // copy referenced version histories
                     new VersionableEditor.Provider(sourceRoot, workspaceName, 
versionCopyConfiguration),
-                    new SameNameSiblingsEditor.Provider()
+                    new SameNameSiblingsEditor.Provider(),
+                    AuthorizableFolderEditor.provider(groupsPath, usersPath)
             )));
 
             // this editor works on the VersionableEditor output, so it can't 
be
@@ -946,6 +980,43 @@ public class RepositoryUpgrade {
         return includes;
     }
 
+    void assertNoLongNames() throws RepositoryException {
+        Session session = source.getRepository().login(null, null);
+        boolean longNameFound = false;
+        try {
+            IndexReader reader = IndexAccessor.getReader(source);
+            if (reader == null) {
+                return;
+            }
+            TermEnum terms = reader.terms(new Term(FieldNames.LOCAL_NAME));
+            while (terms.next()) {
+                Term t = terms.term();
+                if (!FieldNames.LOCAL_NAME.equals(t.field())) {
+                    continue;
+                }
+                String name = t.text();
+                if (NameFilteringNodeState.isNameTooLong(name)) {
+                    TermDocs docs = reader.termDocs(t);
+                    if (docs.next()) {
+                        int docId = docs.doc();
+                        String uuid = 
reader.document(docId).get(FieldNames.UUID);
+                        Node n = session.getNodeByIdentifier(uuid);
+                        logger.warn("Name too long: {}", n.getPath());
+                        longNameFound = true;
+                    }
+                }
+            }
+        } catch (IOException e) {
+            throw new RepositoryException(e);
+        } finally {
+            session.logout();
+        }
+        if (longNameFound) {
+            logger.error("Node with a long name has been found. Please fix the 
content or rerun the migration with {} option.", SKIP_NAME_CHECK);
+            throw new RepositoryException("Node with a long name has been 
found.");
+        }
+    }
+
     static class LoggingCompositeHook implements CommitHook {
         private final Collection<CommitHook> hooks;
         private boolean started = false;

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/blob/LengthCachingDataStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/blob/LengthCachingDataStore.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/blob/LengthCachingDataStore.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/blob/LengthCachingDataStore.java
 Fri Dec 16 11:12:53 2016
@@ -57,27 +57,27 @@ import static com.google.common.base.Pre
 /**
  * A DelegatingDataStore can avoid performing expensive file system access by 
making
  * use of pre computed data related to files in DataStore.
- * <p/>
- * <p>During repository migration actual blob content is not accessed and 
instead
+ * <p>
+ * During repository migration actual blob content is not accessed and instead
  * only the blob length and blob references are accessed. DelegatingDataStore 
can be
  * configured with a mapping file which would be used to determine the length 
of given
- * blob reference.</p>
- * <p/>
+ * blob reference.
+ * <p>
  * Mapping file format
- * <pre><![CDATA[
+ * <pre>{@code
  *     #< length >| < identifier >
  *     4432|dd10bca036f3134352c63e534d4568a3d2ac2fdc
  *     32167|dd10bca036f3134567c63e534d4568a3d2ac2fdc
- * ]]></pre>
- * <p/>
+ * }</pre>
+ * <p>
  * The Configuration:
- * <p/>
- * <pre><![CDATA[
+ * <p>
+ * <pre>{@code
  *  <DataStore 
class="org.apache.jackrabbit.oak.upgrade.blob.LengthCachingDataStore">
  *      <param name="mappingFilePath" value="/path/to/mapping/file" />
  *      <param name="delegateClass" 
value="org.apache.jackrabbit.core.data.FileDataStore" />
  *  </DataStore>
- * ]]></pre>
+ * }</pre>
  */
 public class LengthCachingDataStore extends AbstractDataStore {
     private static final Logger log = 
LoggerFactory.getLogger(LengthCachingDataStore.class);
@@ -292,7 +292,7 @@ public class LengthCachingDataStore exte
             InputStream is = null;
             try {
                 Properties props = new Properties();
-                is = Files.newInputStreamSupplier(configFile).getInput();
+                is = Files.asByteSource(configFile).openStream();
                 props.load(is);
                 PropertiesUtil.populate(delegate, propsToMap(props), false);
                 log.info("Configured the delegating DataStore via {}", 
configFile.getAbsolutePath());

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/CliUtils.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/CliUtils.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/CliUtils.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/CliUtils.java
 Fri Dec 16 11:12:53 2016
@@ -20,35 +20,15 @@ import java.io.IOException;
 import java.io.InputStream;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.jackrabbit.oak.upgrade.cli.parser.CliArgumentException;
-import org.apache.jackrabbit.oak.upgrade.cli.parser.MigrationCliArguments;
-import org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.io.Closer;
 
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-
 public class CliUtils {
 
     private static final Logger log = 
LoggerFactory.getLogger(OakUpgrade.class);
 
-    public static MigrationCliArguments parseOrExit(OptionParser op, String... 
args) {
-        try {
-            OptionSet options = op.parse(args);
-            if (options.has(OptionParserFactory.HELP) || 
options.nonOptionArguments().isEmpty()) {
-                displayUsage();
-                return null;
-            }
-            return new MigrationCliArguments(options);
-        } catch (Exception e) {
-            System.exit(getReturnCode(e));
-            return null;
-        }
-    }
-
     public static void displayUsage() throws IOException {
         System.out.println(getUsage().replace("${command}", "java -jar 
oak-run-*-jr2.jar upgrade"));
     }
@@ -62,18 +42,6 @@ public class CliUtils {
         }
     }
 
-    public static int getReturnCode(Exception e) {
-        if (e.getMessage() != null) {
-            System.err.println(e.getMessage());
-        }
-        if (e instanceof CliArgumentException) {
-            return ((CliArgumentException) e).getExitCode();
-        } else {
-            e.printStackTrace(System.err);
-            return 1;
-        }
-    }
-
     public static void handleSigInt(final Closer closer) {
         Runtime.getRuntime().addShutdownHook(new Thread() {
             @Override

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
 Fri Dec 16 11:12:53 2016
@@ -29,6 +29,8 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.upgrade.RepositorySidegrade;
 import org.apache.jackrabbit.oak.upgrade.RepositoryUpgrade;
+import org.apache.jackrabbit.oak.upgrade.cli.parser.CliArgumentException;
+import org.apache.jackrabbit.oak.upgrade.cli.parser.DatastoreArguments;
 import org.apache.jackrabbit.oak.upgrade.cli.parser.MigrationOptions;
 import org.apache.jackrabbit.oak.upgrade.cli.parser.StoreArguments;
 
@@ -41,44 +43,40 @@ public class MigrationFactory {
 
     protected final StoreArguments stores;
 
+    protected final DatastoreArguments datastores;
+
     protected final Closer closer;
 
-    public MigrationFactory(MigrationOptions options, StoreArguments stores, 
Closer closer) {
+    public MigrationFactory(MigrationOptions options, StoreArguments stores, 
DatastoreArguments datastores, Closer closer) {
         this.options = options;
         this.stores = stores;
+        this.datastores = datastores;
         this.closer = closer;
     }
 
-    public RepositoryUpgrade createUpgrade() throws IOException, 
RepositoryException {
+    public RepositoryUpgrade createUpgrade() throws IOException, 
RepositoryException, CliArgumentException {
         RepositoryContext src = stores.getSrcStore().create(closer);
         BlobStore srcBlobStore = new DataStoreBlobStore(src.getDataStore());
         NodeStore dstStore = createTarget(closer, srcBlobStore);
         return createUpgrade(src, dstStore);
     }
 
-    public RepositorySidegrade createSidegrade() throws IOException {
-        BlobStore srcBlobStore = stores.getSrcBlobStore().create(closer);
+    public RepositorySidegrade createSidegrade() throws IOException, 
CliArgumentException {
+        BlobStore srcBlobStore = datastores.getSrcBlobStore().create(closer);
         NodeStore srcStore = stores.getSrcStore().create(srcBlobStore, closer);
         NodeStore dstStore = createTarget(closer, srcBlobStore);
         return createSidegrade(srcStore, dstStore);
     }
 
     protected NodeStore createTarget(Closer closer, BlobStore srcBlobStore) 
throws IOException {
-        BlobStore dstBlobStore;
-        if (options.isCopyBinariesByReference()) {
-            dstBlobStore = srcBlobStore;
-        } else {
-            dstBlobStore = stores.getDstBlobStore().create(closer);
-        }
+        BlobStore dstBlobStore = 
datastores.getDstBlobStore(srcBlobStore).create(closer);
         NodeStore dstStore = stores.getDstStore().create(dstBlobStore, closer);
         return dstStore;
     }
 
     protected RepositoryUpgrade createUpgrade(RepositoryContext source, 
NodeStore dstStore) {
         RepositoryUpgrade upgrade = new RepositoryUpgrade(source, dstStore);
-        if (source.getDataStore() != null && 
options.isCopyBinariesByReference()) {
-            upgrade.setCopyBinariesByReference(true);
-        }
+        upgrade.setCopyBinariesByReference(datastores.getBlobMigrationCase() 
== DatastoreArguments.BlobMigrationCase.COPY_REFERENCES);
         upgrade.setCopyVersions(options.getCopyVersions());
         upgrade.setCopyOrphanedVersions(options.getCopyOrphanedVersions());
         if (options.getIncludePaths() != null) {
@@ -90,7 +88,8 @@ public class MigrationFactory {
         if (options.getMergePaths() != null) {
             upgrade.setMerges(options.getMergePaths());
         }
-        upgrade.setSkipLongNames(stores.isSkipLongNames());
+        upgrade.setFilterLongNames(!stores.getDstType().isSupportLongNames());
+        upgrade.setCheckLongNames(!options.isSkipNameCheck() && 
!stores.getDstType().isSupportLongNames());
         upgrade.setSkipOnError(!options.isFailOnError());
         upgrade.setEarlyShutdown(options.isEarlyShutdown());
         upgrade.setSkipInitialization(options.isSkipInitialization());
@@ -114,8 +113,9 @@ public class MigrationFactory {
         if (options.getMergePaths() != null) {
             sidegrade.setMerges(options.getMergePaths());
         }
-        sidegrade.setSkipLongNames(stores.isSkipLongNames());
-        sidegrade.setSkipInitialization(options.isSkipInitialization());
+        sidegrade.setFilterLongNames(stores.getSrcType().isSupportLongNames() 
&& !stores.getDstType().isSupportLongNames());
+        sidegrade.setVerify(options.isVerify());
+        sidegrade.setOnlyVerify(options.isOnlyVerify());
         return sidegrade;
     }
 

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/OakUpgrade.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/OakUpgrade.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/OakUpgrade.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/OakUpgrade.java
 Fri Dec 16 11:12:53 2016
@@ -25,8 +25,11 @@ import javax.jcr.RepositoryException;
 import com.google.common.collect.Lists;
 import com.google.common.io.Closer;
 
+import joptsimple.OptionSet;
 import org.apache.jackrabbit.oak.spi.lifecycle.CompositeInitializer;
 import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.upgrade.cli.parser.CliArgumentException;
+import org.apache.jackrabbit.oak.upgrade.cli.parser.DatastoreArguments;
 import org.apache.jackrabbit.oak.upgrade.cli.parser.MigrationCliArguments;
 import org.apache.jackrabbit.oak.upgrade.cli.parser.MigrationOptions;
 import org.apache.jackrabbit.oak.upgrade.cli.parser.OptionParserFactory;
@@ -35,19 +38,39 @@ import org.apache.jackrabbit.oak.upgrade
 public class OakUpgrade {
 
     public static void main(String... args) throws IOException {
-        MigrationCliArguments cliArguments = 
CliUtils.parseOrExit(OptionParserFactory.create(), args);
-        if (cliArguments == null) {
-            return;
+        OptionSet options = OptionParserFactory.create().parse(args);
+        try {
+            MigrationCliArguments cliArguments = new 
MigrationCliArguments(options);
+            if (cliArguments.hasOption(OptionParserFactory.HELP) || 
cliArguments.getArguments().isEmpty()) {
+                CliUtils.displayUsage();
+                return;
+            }
+            migrate(cliArguments);
+        } catch(CliArgumentException e) {
+            if (e.getMessage() != null) {
+                System.err.println(e.getMessage());
+            }
+            System.exit(e.getExitCode());
         }
-        migrate(cliArguments);
     }
 
-    public static void migrate(MigrationCliArguments argumentParser) throws 
IOException {
-        MigrationOptions options = argumentParser.getOptions();
-        StoreArguments stores = argumentParser.getStoreArguments();
+    public static void migrate(MigrationCliArguments argumentParser) throws 
IOException, CliArgumentException {
+        MigrationOptions options = new MigrationOptions(argumentParser);
+        options.logOptions();
+
+        StoreArguments stores = new StoreArguments(options, 
argumentParser.getArguments());
+        stores.logOptions();
+
+        boolean srcEmbedded = stores.srcUsesEmbeddedDatastore();
+        DatastoreArguments datastores = new DatastoreArguments(options, 
stores, srcEmbedded);
+
+        migrate(options, stores, datastores);
+    }
+
+    public static void migrate(MigrationOptions options, StoreArguments 
stores, DatastoreArguments datastores) throws IOException, CliArgumentException 
{
         Closer closer = Closer.create();
         CliUtils.handleSigInt(closer);
-        MigrationFactory factory = new MigrationFactory(options, stores, 
closer);
+        MigrationFactory factory = new MigrationFactory(options, stores, 
datastores, closer);
         try {
             if (stores.getSrcStore().isJcr2()) {
                 upgrade(factory);
@@ -61,11 +84,11 @@ public class OakUpgrade {
         }
     }
 
-    private static void upgrade(MigrationFactory migrationFactory) throws 
IOException, RepositoryException {
+    private static void upgrade(MigrationFactory migrationFactory) throws 
IOException, RepositoryException, CliArgumentException {
         migrationFactory.createUpgrade().copy(createCompositeInitializer());
     }
 
-    private static void sidegrade(MigrationFactory migrationFactory) throws 
IOException, RepositoryException {
+    private static void sidegrade(MigrationFactory migrationFactory) throws 
IOException, RepositoryException, CliArgumentException {
         migrationFactory.createSidegrade().copy();
     }
 

Copied: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/ConstantBlobStoreFactory.java
 (from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java)
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/ConstantBlobStoreFactory.java?p2=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/ConstantBlobStoreFactory.java&p1=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java&r1=1774499&r2=1774571&rev=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/ConstantBlobStoreFactory.java
 Fri Dec 16 11:12:53 2016
@@ -14,16 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.oak.upgrade.cli.node;
+package org.apache.jackrabbit.oak.upgrade.cli.blob;
+
+import com.google.common.io.Closer;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 
 import java.io.IOException;
 
-import org.apache.jackrabbit.oak.spi.blob.BlobStore;
-import org.apache.jackrabbit.oak.spi.state.NodeStore;
+public class ConstantBlobStoreFactory implements BlobStoreFactory {
 
-import com.google.common.io.Closer;
+    private final BlobStore blobStore;
 
-public interface NodeStoreFactory {
+    public ConstantBlobStoreFactory(BlobStore blobStore) {
+        this.blobStore = blobStore;
+    }
 
-    NodeStore create(BlobStore blobStore, Closer closer) throws IOException;
+    @Override
+    public BlobStore create(Closer closer) throws IOException {
+        return blobStore;
+    }
 }

Added: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStore.java?rev=1774571&view=auto
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStore.java
 (added)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStore.java
 Fri Dec 16 11:12:53 2016
@@ -0,0 +1,68 @@
+/*
+ * 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.blob;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+
+/**
+ * Utility BlobStore implementation to be used in tooling that can work with a
+ * FileStore without the need of the DataStore being present locally
+ */
+public class MissingBlobStore implements BlobStore {
+
+    @Override
+    public String writeBlob(InputStream in) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readBlob(String blobId, long pos, byte[] buff, int off,
+            int length) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getBlobLength(String blobId) throws IOException {
+        // best effort length extraction
+        int indexOfSep = blobId.lastIndexOf("#");
+        if (indexOfSep != -1) {
+            return Long.valueOf(blobId.substring(indexOfSep + 1));
+        }
+        return -1;
+    }
+
+    @Override
+    public InputStream getInputStream(String blobId) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getBlobId(String reference) {
+        return reference;
+    }
+
+    @Override
+    public String getReference(String blobId) {
+        return blobId;
+    }
+}

Copied: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStoreFactory.java
 (from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java)
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStoreFactory.java?p2=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStoreFactory.java&p1=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java&r1=1774499&r2=1774571&rev=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/blob/MissingBlobStoreFactory.java
 Fri Dec 16 11:12:53 2016
@@ -14,16 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.oak.upgrade.cli.node;
-
-import java.io.IOException;
+package org.apache.jackrabbit.oak.upgrade.cli.blob;
 
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
-import org.apache.jackrabbit.oak.spi.state.NodeStore;
 
 import com.google.common.io.Closer;
 
-public interface NodeStoreFactory {
+public class MissingBlobStoreFactory implements BlobStoreFactory {
+
+    @Override
+    public BlobStore create(Closer closer) {
+        return new MissingBlobStore();
+    }
 
-    NodeStore create(BlobStore blobStore, Closer closer) throws IOException;
+    @Override
+    public String toString() {
+        return "MissingBlobStore";
+    }
 }

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/JdbcFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/JdbcFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/JdbcFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/JdbcFactory.java
 Fri Dec 16 11:12:53 2016
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.upgrad
 
 import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.rdb.RDBBlobStore;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDataSourceFactory;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -27,6 +28,8 @@ import org.slf4j.LoggerFactory;
 import com.google.common.io.Closer;
 
 import javax.sql.DataSource;
+import java.io.Closeable;
+import java.io.IOException;
 
 public class JdbcFactory implements NodeStoreFactory {
 
@@ -40,7 +43,9 @@ public class JdbcFactory implements Node
 
     private final String password;
 
-    public JdbcFactory(String jdbcUri, int cacheSize, String user, String 
password) {
+    private final boolean readOnly;
+
+    public JdbcFactory(String jdbcUri, int cacheSize, String user, String 
password, boolean readOnly) {
         this.jdbcUri = jdbcUri;
         this.cacheSize = cacheSize;
         if (user == null || password == null) {
@@ -48,16 +53,19 @@ public class JdbcFactory implements Node
         }
         this.user = user;
         this.password = password;
+        this.readOnly = readOnly;
     }
 
     @Override
     public NodeStore create(BlobStore blobStore, Closer closer) {
-        DataSource ds = RDBDataSourceFactory.forJdbcUrl(jdbcUri, user, 
password);
         DocumentMK.Builder builder = MongoFactory.getBuilder(cacheSize);
         if (blobStore != null) {
             builder.setBlobStore(blobStore);
         }
-        builder.setRDBConnection(ds);
+        builder.setRDBConnection(getDataSource(closer));
+        if (readOnly) {
+            log.warn("Read-only mode for the DocumentMK is not available in 
1.4");
+        }
         log.info("Initialized DocumentNodeStore on RDB with Cache size : {} 
MB, Fast migration : {}", cacheSize,
                 builder.isDisableBranches());
         DocumentNodeStore documentNodeStore = builder.getNodeStore();
@@ -65,6 +73,28 @@ public class JdbcFactory implements Node
         return documentNodeStore;
     }
 
+    private DataSource getDataSource(Closer closer) {
+        DataSource ds = RDBDataSourceFactory.forJdbcUrl(jdbcUri, user, 
password);
+        if (ds instanceof Closeable) {
+            closer.register((Closeable)ds);
+        }
+        return ds;
+    }
+
+    @Override
+    public boolean hasExternalBlobReferences() throws IOException {
+        Closer closer = Closer.create();
+        try {
+            DataSource ds = getDataSource(closer);
+            RDBBlobStore blobStore = new RDBBlobStore(ds);
+            return !blobStore.getAllChunkIds(0).hasNext();
+        } catch(Throwable e) {
+            throw closer.rethrow(e);
+        } finally {
+            closer.close();
+        }
+    }
+
     @Override
     public String toString() {
         return String.format("DocumentNodeStore[%s]", jdbcUri);

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/MongoFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/MongoFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/MongoFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/MongoFactory.java
 Fri Dec 16 11:12:53 2016
@@ -16,14 +16,18 @@
  */
 package org.apache.jackrabbit.oak.upgrade.cli.node;
 
+import com.mongodb.DB;
 import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoBlobStore;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 
 import com.google.common.io.Closer;
 import com.mongodb.MongoClient;
 import com.mongodb.MongoClientURI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -31,35 +35,60 @@ import java.net.UnknownHostException;
 
 public class MongoFactory implements NodeStoreFactory {
 
+    private static final Logger log = 
LoggerFactory.getLogger(MongoFactory.class);
+
     private static final long MB = 1024 * 1024;
 
     private final MongoClientURI uri;
 
     private final int cacheSize;
 
-    public MongoFactory(String repoDesc, int cacheSize) {
+    private final boolean readOnly;
+
+    public MongoFactory(String repoDesc, int cacheSize, boolean readOnly) {
         this.uri = new MongoClientURI(repoDesc);
         this.cacheSize = cacheSize;
+        this.readOnly = readOnly;
     }
 
     @Override
     public NodeStore create(BlobStore blobStore, Closer closer) throws 
UnknownHostException {
+        DocumentMK.Builder builder = getBuilder(cacheSize);
+        builder.setMongoDB(getDB(closer));
+        if (blobStore != null) {
+            builder.setBlobStore(blobStore);
+        }
+        if (readOnly) {
+            log.warn("Read-only mode for the DocumentMK is not available in 
1.4");
+        }
+        DocumentNodeStore documentNodeStore = builder.getNodeStore();
+        closer.register(asCloseable(documentNodeStore));
+        return documentNodeStore;
+    }
+
+    private DB getDB(Closer closer) throws UnknownHostException {
         String db;
         if (uri.getDatabase() == null) {
             db = "aem-author"; // assume an author instance
         } else {
             db = uri.getDatabase();
         }
-        DocumentMK.Builder builder = getBuilder(cacheSize);
         MongoClient client = new MongoClient(uri);
         closer.register(asCloseable(client));
-        builder.setMongoDB(client.getDB(db));
-        if (blobStore != null) {
-            builder.setBlobStore(blobStore);
+        return client.getDB(db);
+    }
+
+    @Override
+    public boolean hasExternalBlobReferences() throws IOException {
+        Closer closer = Closer.create();
+        try {
+            MongoBlobStore mongoBlobStore = new MongoBlobStore(getDB(closer));
+            return !mongoBlobStore.getAllChunkIds(0).hasNext();
+        } catch(Throwable e) {
+            throw closer.rethrow(e);
+        } finally {
+            closer.close();
         }
-        DocumentNodeStore documentNodeStore = builder.getNodeStore();
-        closer.register(asCloseable(documentNodeStore));
-        return documentNodeStore;
     }
 
     static Closeable asCloseable(final DocumentNodeStore documentNodeStore) {

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
 Fri Dec 16 11:12:53 2016
@@ -26,4 +26,6 @@ import com.google.common.io.Closer;
 public interface NodeStoreFactory {
 
     NodeStore create(BlobStore blobStore, Closer closer) throws IOException;
+
+    boolean hasExternalBlobReferences() throws IOException;
 }

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/SegmentFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/SegmentFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/SegmentFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/SegmentFactory.java
 Fri Dec 16 11:12:53 2016
@@ -20,38 +20,112 @@ import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector;
+import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeBuilder;
+import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState;
 import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore;
 import org.apache.jackrabbit.oak.plugins.segment.file.FileStore;
 import org.apache.jackrabbit.oak.plugins.segment.file.FileStore.Builder;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+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 com.google.common.io.Closer;
 
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
 public class SegmentFactory implements NodeStoreFactory {
 
     private final File dir;
 
-    private final boolean mmap;
+    private final boolean disableMmap;
+
+    private final boolean readOnly;
 
-    public SegmentFactory(String directory, boolean mmap) {
+    public SegmentFactory(String directory, boolean disableMmap, boolean 
readOnly) {
         this.dir = new File(directory);
-        this.mmap = mmap;
+        this.disableMmap = disableMmap;
+        this.readOnly = readOnly;
+        createDirectoryIfMissing(dir);
         if (!dir.isDirectory()) {
             throw new IllegalArgumentException("Not a directory: " + 
dir.getPath());
         }
     }
 
+    private void createDirectoryIfMissing(File directory) {
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+    }
+
     @Override
     public NodeStore create(BlobStore blobStore, Closer closer) throws 
IOException {
-        Builder builder = FileStore.newFileStore(new File(dir, 
"segmentstore"));
-        if (blobStore != null) {
-            builder.withBlobStore(blobStore);
+        File directory = new File(dir, "segmentstore");
+
+        final FileStore fs;
+        if (readOnly) {
+            if (disableMmap) {
+                fs = new FileStore.ReadOnlyStore(directory, 0, false, 
blobStore);
+            } else {
+                fs = new FileStore.ReadOnlyStore(directory, blobStore);
+            }
+        } else {
+            Builder builder = FileStore.newFileStore(directory);
+            if (blobStore != null) {
+                builder.withBlobStore(blobStore);
+            }
+            builder.withMaxFileSize(256);
+            if (disableMmap) {
+                builder.withMemoryMapping(false);
+            } else {
+                builder.withDefaultMemoryMapping();
+            }
+            fs = builder.create();
         }
-        builder.withMaxFileSize(256).withMemoryMapping(mmap);
-        FileStore fs = builder.create();
         closer.register(asCloseable(fs));
-        return SegmentNodeStore.newSegmentNodeStore(fs).create();
+
+        return new 
TarNodeStore(SegmentNodeStore.newSegmentNodeStore(fs).create(), new 
TarNodeStore.SuperRootProvider() {
+            @Override
+            public void setSuperRoot(NodeBuilder builder) {
+                checkArgument(builder instanceof SegmentNodeBuilder);
+                SegmentNodeBuilder segmentBuilder = (SegmentNodeBuilder) 
builder;
+                SegmentNodeState lastRoot = (SegmentNodeState) getSuperRoot();
+
+                if (!lastRoot.getRecordId().equals(((SegmentNodeState) 
segmentBuilder.getBaseState()).getRecordId())) {
+                    throw new IllegalArgumentException("The new head is out of 
date");
+                }
+
+                fs.setHead(lastRoot, ((SegmentNodeBuilder) 
builder).getNodeState());
+            }
+
+            @Override
+            public NodeState getSuperRoot() {
+                return fs.getHead();
+            }
+        });
+    }
+
+    @Override
+    public boolean hasExternalBlobReferences() throws IOException {
+        FileStore fs = new FileStore.ReadOnlyStore(new File(dir, 
"segmentstore"), 0, false);
+        try {
+            fs.getTracker().collectBlobReferences(new ReferenceCollector() {
+                @Override
+                public void addReference(String reference, @Nullable String 
nodeId) {
+                    // FIXME the collector should allow to stop processing
+                    // see java.nio.file.FileVisitor
+                    throw new ExternalBlobFound();
+                }
+            });
+            return false;
+        } catch (ExternalBlobFound e) {
+            return true;
+        } finally {
+            fs.close();
+        }
     }
 
     public File getRepositoryDir() {
@@ -71,4 +145,7 @@ public class SegmentFactory implements N
     public String toString() {
         return String.format("SegmentNodeStore[%s]", dir);
     }
+
+    private static class ExternalBlobFound extends RuntimeException {
+    }
 }

Modified: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/StoreFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/StoreFactory.java?rev=1774571&r1=1774570&r2=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/StoreFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/StoreFactory.java
 Fri Dec 16 11:12:53 2016
@@ -59,4 +59,12 @@ public class StoreFactory {
     public boolean isJcr2() {
         return jcr2Factory != null;
     }
+
+    public boolean hasExternalBlobReferences() throws IOException {
+        if (isJcr2()) {
+            return true;
+        } else {
+            return nodeStoreFactory.hasExternalBlobReferences();
+        }
+    }
 }

Copied: 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java
 (from r1774499, 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java)
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java?p2=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java&p1=jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java&r1=1774499&r2=1774571&rev=1774571&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/NodeStoreFactory.java
 (original)
+++ 
jackrabbit/oak/branches/1.4/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/node/TarNodeStore.java
 Fri Dec 16 11:12:53 2016
@@ -16,14 +16,40 @@
  */
 package org.apache.jackrabbit.oak.upgrade.cli.node;
 
-import java.io.IOException;
-
-import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+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.spi.state.ProxyNodeStore;
+
+public class TarNodeStore extends ProxyNodeStore {
+
+    private final NodeStore ns;
+
+    private final SuperRootProvider superRootProvider;
+
+    public TarNodeStore(NodeStore ns, SuperRootProvider superRootProvider) {
+        this.ns = ns;
+        this.superRootProvider = superRootProvider;
+    }
+
+    public void setSuperRoot(NodeBuilder builder) {
+        superRootProvider.setSuperRoot(builder);
+    }
+
+    public NodeState getSuperRoot() {
+        return superRootProvider.getSuperRoot();
+    }
+
+    @Override
+    protected NodeStore getNodeStore() {
+        return ns;
+    }
+
+    interface SuperRootProvider {
 
-import com.google.common.io.Closer;
+        void setSuperRoot(NodeBuilder builder);
 
-public interface NodeStoreFactory {
+        NodeState getSuperRoot();
 
-    NodeStore create(BlobStore blobStore, Closer closer) throws IOException;
+    }
 }


Reply via email to