Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java (revision 1730474) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/Mode.java (working copy) @@ -42,6 +42,7 @@ TARMKDIFF("tarmkdiff", new FileStoreDiffCommand()), TARMKRECOVERY("tarmkrecovery", new FileStoreRevisionRecoveryCommand()), DUMPDATASTOREREFS("dumpdatastorerefs", new DumpDataStoreReferencesCommand()), + RESETCLUSTERID("resetclusterid", new ResetClusterIdCommand()), HELP("help", new HelpCommand()); private final String name; Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/ResetClusterIdCommand.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/ResetClusterIdCommand.java (revision 0) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/ResetClusterIdCommand.java (working copy) @@ -0,0 +1,116 @@ +/* + * 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.run; + +import static org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.openFileStore; + +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.plugins.document.DocumentMK; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.identifier.ClusterRepositoryInfo; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore; +import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; +import org.apache.jackrabbit.oak.spi.commit.CommitInfo; +import org.apache.jackrabbit.oak.spi.commit.EmptyHook; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeStore; + +import com.google.common.io.Closer; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientURI; +import com.mongodb.MongoURI; + +/** + * OFFLINE utility to delete the clusterId stored as hidden + * property as defined by ClusterRepositoryInfo. + *
+ * This utility is meant to be the only mechanism to delete + * this id and yes, it is meant to be used offline only + * (as otherwise this would correspond to breaking the + * requirement that the clusterId be stable and persistent). + *
+ * Target use case for this tool is to avoid duplicate
+ * clusterIds after a repository was cloned.
+ */
+public class ResetClusterIdCommand implements Command {
+
+ private static void deleteClusterId(NodeStore store) {
+ NodeBuilder builder = store.getRoot().builder();
+ NodeBuilder clusterConfigNode = builder.getChildNode(
+ ClusterRepositoryInfo.CLUSTER_CONFIG_NODE);
+
+ if (!clusterConfigNode.exists()) {
+ // if it doesn't exist, then there is no way to delete
+ System.out.println("clusterId was never set or already deleted.");
+ return;
+ }
+
+ if (!clusterConfigNode.hasProperty(ClusterRepositoryInfo.CLUSTER_ID_PROP)) {
+ // the config node exists, but the clusterId not
+ // so again, no way to delete
+ System.out.println("clusterId was never set or already deleted.");
+ return;
+ }
+ String oldClusterId = clusterConfigNode.getProperty(ClusterRepositoryInfo.CLUSTER_ID_PROP)
+ .getValue(Type.STRING);
+ clusterConfigNode.removeProperty(ClusterRepositoryInfo.CLUSTER_ID_PROP);
+ try {
+ store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ System.out.println("clusterId deleted successfully. (old id was " + oldClusterId + ")");
+ } catch (CommitFailedException e) {
+ System.err.println("Failed to delete clusterId due to exception: "+e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void execute(String... args) throws Exception {
+ if (args.length != 1) {
+ System.out
+ .println("usage: resetclusterid {