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 {|}"); + System.exit(1); + } + + Closer closer = Closer.create(); + try { + NodeStore store; + if (args[0].startsWith(MongoURI.MONGODB_PREFIX)) { + MongoClientURI uri = new MongoClientURI(args[0]); + MongoClient client = new MongoClient(uri); + final DocumentNodeStore dns = new DocumentMK.Builder() + .setMongoDB(client.getDB(uri.getDatabase())) + .getNodeStore(); + closer.register(Utils.asCloseable(dns)); + store = dns; + } else { + FileStore fs = openFileStore(args[0]); + closer.register(Utils.asCloseable(fs)); + store = SegmentNodeStore.newSegmentNodeStore(fs).create(); + } + + deleteClusterId(store); + } catch (Throwable e) { + throw closer.rethrow(e); + } finally { + closer.close(); + } + + } + +} Property changes on: oak-run/src/main/java/org/apache/jackrabbit/oak/run/ResetClusterIdCommand.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property