/** * Copyright 2016 LinkedIn Corp. All rights reserved. * * Licensed 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. */ package com.github.ambry.clustermap; import com.github.ambry.config.ClusterMapConfig; import com.github.ambry.config.VerifiableProperties; import com.github.ambry.tools.util.ToolUtils; import com.github.ambry.utils.Utils; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Properties; import joptsimple.ArgumentAcceptingOptionSpec; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; import org.json.JSONObject; /** * Helps to perform all operations related to a partition */ public class PartitionManager { public static void main(String args[]) { try { OptionParser parser = new OptionParser(); ArgumentAcceptingOptionSpec<String> operationTypeOpt = parser.accepts("operationType", " REQUIRED: The type of operation to perform on the partition. Currently supported" + " operations are 'AddPartition', 'AddReplicas'") .withRequiredArg() .describedAs("operation_type") .ofType(String.class); ArgumentAcceptingOptionSpec<String> hardwareLayoutPathOpt = parser.accepts("hardwareLayoutPath", " REQUIRED: The path to the hardware layout map") .withRequiredArg() .describedAs("hardware_layout_path") .ofType(String.class); ArgumentAcceptingOptionSpec<String> partitionLayoutPathOpt = parser.accepts("partitionLayoutPath", "REQUIRED: The path to the partition layout map. If outputPartitionLayoutPath is not defined," + "this file is updated with the new partitions") .withRequiredArg() .describedAs("partition_layout_path") .ofType(String.class); ArgumentAcceptingOptionSpec<String> outputPartitionLayoutPathOpt = parser.accepts("outputPartitionLayoutPath", "The path to the output partition layout map. The file is updated with the new partitions") .withOptionalArg() .describedAs("output_partition_layout_path") .ofType(String.class); ArgumentAcceptingOptionSpec<Integer> numberOfPartitionsOpt = parser.accepts("numberOfPartitionsToAdd", "The number of partitions to add") .withOptionalArg() .ofType(Integer.class); ArgumentAcceptingOptionSpec<Integer> numberOfReplicasPerDatacenterOpt = parser.accepts("numberOfReplicasPerDatacenter", "The number of replicas for the partition per datacenter when adding partitions") .withOptionalArg() .ofType(Integer.class); ArgumentAcceptingOptionSpec<Long> replicaCapacityInBytesOpt = parser.accepts("replicaCapacityInBytes", "The capacity of each replica in bytes for the partitions to add") .withOptionalArg() .ofType(Long.class); ArgumentAcceptingOptionSpec<String> partitionIdsToAddReplicasToOpt = parser.accepts("partitionIdToAddReplicasTo", "The partitionIds to add replicas to. This can either take a " + "comma separated list of partitions to add replicas to or '.' to add replicas to all partitions in " + "the partitionLayout ").withOptionalArg().ofType(String.class); ArgumentAcceptingOptionSpec<String> datacenterToAddReplicasToOpt = parser.accepts("datacenterToAddReplicasTo", "The data center to which replicas need to be added to") .withOptionalArg() .ofType(String.class); String attemptNonRackAwareOnFailureFlag = "attemptNonRackAwareOnFailure"; parser.accepts(attemptNonRackAwareOnFailureFlag, "If a rack-aware partition allocation cannot be found, attempt a non rack-aware one"); OptionSet options = parser.parse(args); ArrayList<OptionSpec> listOpt = new ArrayList<OptionSpec>(); listOpt.add(hardwareLayoutPathOpt); listOpt.add(operationTypeOpt); ToolUtils.ensureOrExit(listOpt, options, parser); String hardwareLayoutPath = options.valueOf(hardwareLayoutPathOpt); String partitionLayoutPath = options.valueOf(partitionLayoutPathOpt); String outputPartitionLayoutPath = options.has(outputPartitionLayoutPathOpt) ? options.valueOf(outputPartitionLayoutPathOpt) : partitionLayoutPath; String operationType = options.valueOf(operationTypeOpt); boolean attemptNonRackAwareOnFailure = options.has(attemptNonRackAwareOnFailureFlag); String fileString = null; try { fileString = Utils.readStringFromFile(partitionLayoutPath); } catch (FileNotFoundException e) { System.out.println("Partition layout path not found. Creating new file"); } StaticClusterManager manager = null; ClusterMapConfig clusterMapConfig = new ClusterMapConfig(new VerifiableProperties(new Properties())); if (fileString == null) { manager = (new StaticClusterAgentsFactory(clusterMapConfig, new PartitionLayout( new HardwareLayout(new JSONObject(Utils.readStringFromFile(hardwareLayoutPath)), clusterMapConfig)))).getClusterMap(); } else { manager = (new StaticClusterAgentsFactory(clusterMapConfig, hardwareLayoutPath, partitionLayoutPath)).getClusterMap(); } if (operationType.compareToIgnoreCase("AddPartition") == 0) { listOpt.add(numberOfPartitionsOpt); listOpt.add(numberOfReplicasPerDatacenterOpt); listOpt.add(replicaCapacityInBytesOpt); ToolUtils.ensureOrExit(listOpt, options, parser); int numberOfPartitions = options.valueOf(numberOfPartitionsOpt); int numberOfReplicas = options.valueOf(numberOfReplicasPerDatacenterOpt); long replicaCapacityInBytes = options.valueOf(replicaCapacityInBytesOpt); manager.allocatePartitions(numberOfPartitions, numberOfReplicas, replicaCapacityInBytes, attemptNonRackAwareOnFailure); } else if (operationType.compareToIgnoreCase("AddReplicas") == 0) { listOpt.add(partitionIdsToAddReplicasToOpt); listOpt.add(datacenterToAddReplicasToOpt); listOpt.add(partitionLayoutPathOpt); ToolUtils.ensureOrExit(listOpt, options, parser); String partitionIdsToAddReplicas = options.valueOf(partitionIdsToAddReplicasToOpt); String datacenterToAddReplicasTo = options.valueOf(datacenterToAddReplicasToOpt); if (partitionIdsToAddReplicas.compareToIgnoreCase(".") == 0) { for (PartitionId partitionId : manager.getAllPartitionIds()) { manager.addReplicas(partitionId, datacenterToAddReplicasTo, attemptNonRackAwareOnFailure); } } else { String[] partitionIds = partitionIdsToAddReplicas.split(","); for (String partitionId : partitionIds) { for (PartitionId partitionInCluster : manager.getAllPartitionIds()) { if (partitionInCluster.isEqual(partitionId)) { manager.addReplicas(partitionInCluster, datacenterToAddReplicasTo, attemptNonRackAwareOnFailure); } } } } } manager.persist(hardwareLayoutPath, outputPartitionLayoutPath); } catch (Exception e) { System.out.println("Error while executing partition command " + e); } } }