Author: tomekr
Date: Wed Jul 27 12:24:42 2016
New Revision: 1754257
URL: http://svn.apache.org/viewvc?rev=1754257&view=rev
Log:
OAK-4500: Create tooling for reducing a document-based repository to a list of
paths
Added:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/IndexCopier.java
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeIndexTest.java
Modified:
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/cli/MigrationFactory.java
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java
Added:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/IndexCopier.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/IndexCopier.java?rev=1754257&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/IndexCopier.java
(added)
+++
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/IndexCopier.java
Wed Jul 27 12:24:42 2016
@@ -0,0 +1,136 @@
+/*
+ * 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.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.upgrade.nodestate.NodeStateCopier;
+
+import java.util.Set;
+
+import static java.util.Collections.singleton;
+import static org.apache.commons.lang.StringUtils.isEmpty;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.UNIQUE_PROPERTY_NAME;
+
+public final class IndexCopier {
+
+ private IndexCopier() {
+ }
+
+ /**
+ * Copy all index definition and data from sourceRoot to targetRoot. The
+ * indexing data is filtered to include only content related to the passed
+ * list of paths.
+ *
+ * @param sourceRoot the source
+ * @param targetRoot the target
+ * @param includes indexing data for these paths will be copied
+ */
+ public static void copy(NodeState sourceRoot, NodeBuilder targetRoot,
Set<String> includes) {
+ NodeState oakIndex = sourceRoot.getChildNode(INDEX_DEFINITIONS_NAME);
+ NodeBuilder targetOakIndex = copySingleNode(oakIndex, targetRoot,
INDEX_DEFINITIONS_NAME);
+
+ for (ChildNodeEntry child : oakIndex.getChildNodeEntries()) {
+ NodeState indexDef = child.getNodeState();
+ String type = indexDef.getString(TYPE_PROPERTY_NAME);
+ if (isEmpty(type)) {
+ continue;
+ }
+
+ NodeBuilder targetIndexDef = copySingleNode(child, targetOakIndex);
+
+ switch (type) {
+ case "property":
+ if (indexDef.getBoolean(UNIQUE_PROPERTY_NAME)) {
+ copyUniqueIndex(indexDef, targetIndexDef, includes);
+ } else {
+ copyMirrorIndex(indexDef, targetIndexDef, includes);
+ }
+ break;
+
+ case "counter":
+ copyMirrorIndex(indexDef, targetIndexDef, includes);
+
+ case "lucene":
+ copyLuceneIndex(indexDef, targetIndexDef, includes);
+
+ default:
+ break;
+ }
+ }
+ }
+
+ private static void copyUniqueIndex(NodeState indexDef, NodeBuilder
targetIndexDef, Set<String> includes) {
+ NodeState indexNode = indexDef.getChildNode(INDEX_CONTENT_NODE_NAME);
+ NodeBuilder targetIndexNode = copySingleNode(indexNode,
targetIndexDef, INDEX_CONTENT_NODE_NAME);
+
+ for (ChildNodeEntry attr : indexNode.getChildNodeEntries()) {
+ Iterable<String> entries = attr.getNodeState().getStrings("entry");
+ if (entries != null) {
+ for (String e : entries) {
+ if (startsWithAny(e, includes)) {
+ copySingleNode(attr, targetIndexNode);
+ }
+ }
+ }
+ }
+ }
+
+ private static void copyMirrorIndex(NodeState indexDef, NodeBuilder
targetIndexDef, Set<String> includes) {
+ NodeState indexNode = indexDef.getChildNode(INDEX_CONTENT_NODE_NAME);
+ NodeBuilder targetIndexNode = copySingleNode(indexNode,
targetIndexDef, INDEX_CONTENT_NODE_NAME);
+
+ for (ChildNodeEntry attr : indexNode.getChildNodeEntries()) {
+ NodeBuilder targetAttr = copySingleNode(attr, targetIndexNode);
+ NodeStateCopier.builder()
+ .include(includes)
+ .copy(attr.getNodeState(), targetAttr);
+ }
+ }
+
+ private static void copyLuceneIndex(NodeState indexDef, NodeBuilder
targetIndexDef, Set<String> includes) {
+ NodeStateCopier.builder()
+ .include(singleton("/"))
+ .copy(indexDef, targetIndexDef);
+ }
+
+ private static NodeBuilder copySingleNode(ChildNodeEntry source,
NodeBuilder targetParent) {
+ return copySingleNode(source.getNodeState(), targetParent,
source.getName());
+ }
+
+ private static NodeBuilder copySingleNode(NodeState source, NodeBuilder
targetParent, String name) {
+ NodeBuilder target = targetParent.child(name);
+ for (PropertyState p : source.getProperties()) {
+ target.setProperty(p);
+ }
+ return target;
+ }
+
+ private static boolean startsWithAny(String subject, Iterable<String>
patterns) {
+ for (String p : patterns) {
+ if (subject.startsWith(p)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
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=1754257&r1=1754256&r2=1754257&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
Wed Jul 27 12:24:42 2016
@@ -91,6 +91,8 @@ public class RepositorySidegrade {
*/
private Set<String> mergePaths = DEFAULT_MERGE_PATHS;
+ private boolean includeIndex = false;
+
private boolean filterLongNames = true;
private boolean skipInitialization = false;
@@ -187,6 +189,9 @@ public class RepositorySidegrade {
this.excludePaths = copyOf(checkNotNull(excludes));
}
+ public void setIncludeIndex(boolean includeIndex) {
+ this.includeIndex = includeIndex;
+ }
/**
* Sets the paths that should be merged when the source repository
@@ -273,8 +278,19 @@ public class RepositorySidegrade {
private void copyState(NodeState sourceRoot, NodeBuilder targetRoot)
throws CommitFailedException {
copyWorkspace(sourceRoot, targetRoot);
+ if (includeIndex) {
+ IndexCopier.copy(sourceRoot, targetRoot, includePaths);
+ }
+
+ boolean isRemoveCheckpointReferences = false;
if (!copyCheckpoints(targetRoot)) {
LOG.info("Copying checkpoints is not supported for this
combination of node stores");
+ isRemoveCheckpointReferences = true;
+ }
+ if (!DEFAULT_INCLUDE_PATHS.equals(includePaths)) {
+ isRemoveCheckpointReferences = true;
+ }
+ if (isRemoveCheckpointReferences) {
removeCheckpointReferences(targetRoot);
}
Modified:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java?rev=1754257&r1=1754256&r2=1754257&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
(original)
+++
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/MigrationFactory.java
Wed Jul 27 12:24:42 2016
@@ -117,6 +117,7 @@ public class MigrationFactory {
}
sidegrade.setFilterLongNames(stores.getSrcType().isSupportLongNames()
&& !stores.getDstType().isSupportLongNames());
sidegrade.setSkipInitialization(options.isSkipInitialization());
+ sidegrade.setIncludeIndex(options.isIncludeIndex());
return sidegrade;
}
Modified:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java?rev=1754257&r1=1754256&r2=1754257&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
(original)
+++
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/MigrationOptions.java
Wed Jul 27 12:24:42 2016
@@ -46,6 +46,8 @@ public class MigrationOptions {
private final String[] mergePaths;
+ private final boolean includeIndex;
+
private final boolean failOnError;
private final boolean earlyShutdown;
@@ -78,6 +80,7 @@ public class MigrationOptions {
this.includePaths =
split(args.getOption(OptionParserFactory.INCLUDE_PATHS));
this.excludePaths =
split(args.getOption(OptionParserFactory.EXCLUDE_PATHS));
this.mergePaths =
split(args.getOption(OptionParserFactory.MERGE_PATHS));
+ this.includeIndex = args.hasOption(OptionParserFactory.INCLUDE_INDEX);
this.failOnError = args.hasOption(OptionParserFactory.FAIL_ON_ERROR);
this.earlyShutdown =
args.hasOption(OptionParserFactory.EARLY_SHUTDOWN);
this.skipInitialization =
args.hasOption(OptionParserFactory.SKIP_INIT);
@@ -133,6 +136,10 @@ public class MigrationOptions {
return skipNameCheck;
}
+ public boolean isIncludeIndex() {
+ return includeIndex;
+ }
+
private void logOptions() {
if (copyBinariesByReference) {
log.info("DataStore needs to be shared with new repository");
@@ -180,6 +187,10 @@ public class MigrationOptions {
log.info("Test for long-named nodes will be disabled");
}
+ if (includeIndex) {
+ log.info("Index data for the paths {} will be copied", (Object)
includePaths);
+ }
+
log.info("Cache size: {} MB", cacheSizeInMB);
}
Modified:
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java?rev=1754257&r1=1754256&r2=1754257&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
(original)
+++
jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/cli/parser/OptionParserFactory.java
Wed Jul 27 12:24:42 2016
@@ -74,6 +74,8 @@ public class OptionParserFactory {
public static final String SKIP_NAME_CHECK = "skip-name-check";
+ public static final String INCLUDE_INDEX = "include-index";
+
public static OptionParser create() {
OptionParser op = new OptionParser();
addUsageOptions(op);
@@ -122,6 +124,7 @@ public class OptionParserFactory {
.ofType(String.class);
op.accepts(MERGE_PATHS, "Comma-separated list of paths to merge during
copy.").withRequiredArg()
.ofType(String.class);
+ op.accepts(INCLUDE_INDEX, "Copy index data for paths specified in the
" + INCLUDE_PATHS + " option");
}
private static void addVersioningOptions(OptionParser op) {
Added:
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeIndexTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeIndexTest.java?rev=1754257&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeIndexTest.java
(added)
+++
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/IncludeIndexTest.java
Wed Jul 27 12:24:42 2016
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.upgrade;
+
+import com.google.common.base.Joiner;
+import org.apache.jackrabbit.oak.commons.IOUtils;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.upgrade.cli.AbstractOak2OakTest;
+import org.apache.jackrabbit.oak.upgrade.cli.OakUpgrade;
+import org.apache.jackrabbit.oak.upgrade.cli.container.BlobStoreContainer;
+import org.apache.jackrabbit.oak.upgrade.cli.container.FileDataStoreContainer;
+import org.apache.jackrabbit.oak.upgrade.cli.container.MongoNodeStoreContainer;
+import org.apache.jackrabbit.oak.upgrade.cli.container.NodeStoreContainer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.io.IOException;
+
+import static junit.framework.TestCase.assertTrue;
+import static
org.apache.jackrabbit.oak.upgrade.cli.container.MongoNodeStoreContainer.isMongoAvailable;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeTrue;
+
+public class IncludeIndexTest extends AbstractOak2OakTest {
+
+ private static final Logger log =
LoggerFactory.getLogger(IncludeIndexTest.class);
+
+ private final BlobStoreContainer blob;
+
+ private final NodeStoreContainer source;
+
+ private final NodeStoreContainer destination;
+
+ private NodeStore nodeStore;
+
+ @Before
+ public void prepare() throws Exception {
+ NodeStore source = getSourceContainer().open();
+ try {
+ initContent(source);
+ } finally {
+ getSourceContainer().close();
+ }
+
+ String[] args = getArgs();
+ log.info("oak2oak {}", Joiner.on(' ').join(args));
+ OakUpgrade.main(args);
+
+ nodeStore = destination.open();
+ }
+
+ @After
+ public void clean() throws IOException {
+ IOUtils.closeQuietly(getDestinationContainer());
+ getDestinationContainer().clean();
+ getSourceContainer().clean();
+ }
+
+ public IncludeIndexTest() throws IOException {
+ assumeTrue(isMongoAvailable());
+ blob = new FileDataStoreContainer();
+ source = new MongoNodeStoreContainer(blob);
+ destination = new MongoNodeStoreContainer(blob);
+ }
+
+ @Override
+ protected NodeStoreContainer getSourceContainer() {
+ return source;
+ }
+
+ @Override
+ protected NodeStoreContainer getDestinationContainer() {
+ return destination;
+ }
+
+ @Override
+ protected String[] getArgs() {
+ return new String[] { "--src-datastore", blob.getDescription(),
"--copy-versions=false", "--skip-init", "--include-index",
"--include-paths=/apps,/libs", source.getDescription(),
destination.getDescription() };
+ }
+
+ @Test
+ public void validateMigration() throws RepositoryException, IOException {
+
assertNodeExists("/oak:index/nodetype/:index/nt%3Afile/libs/sling/xss/config.xml");
+ assertNodeExists("/oak:index/uuid/:index/" +
getUuid("/apps/repl/components/repl/repl.html/jcr:content"));
+
+ assertNodeMissing("/oak:index/nodetype/:index/nt%3Afile/sling.css");
+ assertNodeMissing("/oak:index/uuid/:index/" +
getUuid("/index.html/jcr:content"));
+ }
+
+ private String getUuid(String path) {
+ return getNode(path).getString("jcr:uuid");
+ }
+
+ private void assertNodeMissing(String path) {
+ assertFalse(getNode(path).exists());
+ }
+
+ private void assertNodeExists(String path) {
+ assertTrue(getNode(path).exists());
+ }
+
+ private NodeState getNode(String path) {
+ NodeState ns = nodeStore.getRoot();
+ for (String element : PathUtils.elements(path)) {
+ ns = ns.getChildNode(element);
+ }
+ return ns;
+ }
+}
\ No newline at end of file
Modified:
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java?rev=1754257&r1=1754256&r2=1754257&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java
(original)
+++
jackrabbit/oak/trunk/oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/cli/AbstractOak2OakTest.java
Wed Jul 27 12:24:42 2016
@@ -115,7 +115,7 @@ public abstract class AbstractOak2OakTes
}
}
- private void initContent(NodeStore target) throws IOException,
RepositoryException, CommitFailedException {
+ protected void initContent(NodeStore target) throws IOException,
RepositoryException, CommitFailedException {
NodeStore initialContent = testContent.open();
try {
RepositorySidegrade sidegrade = new
RepositorySidegrade(initialContent, target);