/*
* Copyright 2017 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 java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.helix.HelixAdmin;
import org.apache.helix.model.ClusterConstraints;
import org.apache.helix.model.ConstraintItem;
import org.apache.helix.model.ExternalView;
import org.apache.helix.model.HelixConfigScope;
import org.apache.helix.model.IdealState;
import org.apache.helix.model.InstanceConfig;
import org.apache.helix.model.StateModelDefinition;
/**
* Mock implementation of {@link HelixAdmin} which stores all information internally.
*/
public class MockHelixAdmin implements HelixAdmin {
private String clusterName;
private final Map<String, InstanceConfig> instanceNameToinstanceConfigs = new HashMap<>();
private final Map<String, IdealState> resourcesToIdealStates = new HashMap<>();
private final Set<String> upInstances = new HashSet<>();
private final Set<String> downInstances = new HashSet<>();
private long totalDiskCount = 0;
private final List<MockHelixManager> helixManagersForThisAdmin = new ArrayList<>();
private Map<String, Set<String>> partitionToInstances = new HashMap<>();
private Map<String, PartitionState> partitionToPartitionStates = new HashMap<>();
private long totalDiskCapacity;
@Override
public List<String> getClusters() {
return Collections.singletonList(clusterName);
}
@Override
public boolean addCluster(String clusterName) {
if (this.clusterName == null) {
this.clusterName = clusterName;
return true;
} else {
throw new IllegalStateException("A cluster has already been added");
}
}
@Override
public void addStateModelDef(String clusterName, String stateModelDef, StateModelDefinition record) {
}
@Override
public void addInstance(String clusterName, InstanceConfig instanceConfig) {
instanceNameToinstanceConfigs.put(instanceConfig.getInstanceName(), instanceConfig);
upInstances.add(instanceConfig.getInstanceName());
Map<String, Map<String, String>> diskInfos = instanceConfig.getRecord().getMapFields();
totalDiskCount += diskInfos.size();
for (Map<String, String> diskInfo : diskInfos.values()) {
totalDiskCapacity += Long.valueOf(diskInfo.get(ClusterMapUtils.DISK_CAPACITY_STR));
}
}
@Override
public void addResource(String clusterName, String resourceName, IdealState idealstate) {
resourcesToIdealStates.put(resourceName, idealstate);
for (String partition : idealstate.getPartitionSet()) {
if (partitionToInstances.get(partition) == null) {
Set<String> instanceSet = new HashSet<>();
partitionToInstances.put(partition, instanceSet);
partitionToPartitionStates.put(partition, PartitionState.READ_WRITE);
}
partitionToInstances.get(partition).addAll(idealstate.getInstanceSet(partition));
}
}
@Override
public List<String> getResourcesInCluster(String clusterName) {
List<String> resources = new ArrayList<>();
resources.addAll(resourcesToIdealStates.keySet());
return resources;
}
@Override
public IdealState getResourceIdealState(String clusterName, String resourceName) {
return resourcesToIdealStates.get(resourceName);
}
@Override
public List<String> getInstancesInCluster(String clusterName) {
List<String> instances = new ArrayList<>();
instances.addAll(instanceNameToinstanceConfigs.keySet());
return instances;
}
@Override
public InstanceConfig getInstanceConfig(String clusterName, String instanceName) {
return instanceNameToinstanceConfigs.get(instanceName);
}
@Override
public boolean setInstanceConfig(String clusterName, String instanceName, InstanceConfig instanceConfig) {
instanceNameToinstanceConfigs.put(instanceName, instanceConfig);
return true;
}
/**
* Associate the given Helix manager with this admin.
* @param helixManager the {@link MockHelixManager} to associate this admin with.
*/
void addHelixManager(MockHelixManager helixManager) {
helixManagersForThisAdmin.add(helixManager);
}
/**
* @return all instances registered via this Helix admin that are up.
*/
List<String> getUpInstances() {
List<String> upList = new ArrayList<>();
upList.addAll(upInstances);
return upList;
}
/**
* Bring up the given instance (that was registered via this Helix admin).
* @param instance the instance to be brought up.
*/
void bringInstanceUp(String instance) {
downInstances.remove(instance);
upInstances.add(instance);
triggerLiveInstanceChangeNotification();
}
/**
* @return all instances registered via this Helix admin that are down.
*/
List<String> getDownInstances() {
List<String> downList = new ArrayList<>();
downList.addAll(downInstances);
return downList;
}
/**
* Bring down the given instance (that was registered via this Helix admin).
* @param instance the instance to be brought down.
*/
void bringInstanceDown(String instance) {
downInstances.add(instance);
upInstances.remove(instance);
triggerLiveInstanceChangeNotification();
}
/**
* Sets the state of a partition
* @param partition partition for which state needs to be updated
* @param partitionState {@link PartitionState} that needs to be set
*/
void setPartitionState(String partition, PartitionState partitionState) {
for (IdealState entry : resourcesToIdealStates.values()) {
for (String partitionInIdealState : entry.getPartitionSet()) {
if (partitionInIdealState.equals(partition)) {
partitionToPartitionStates.put(partition, partitionState);
}
}
}
}
/**
* Trigger a live instance change notification.
*/
private void triggerLiveInstanceChangeNotification() {
for (MockHelixManager helixManager : helixManagersForThisAdmin) {
helixManager.triggerLiveInstanceNotification();
}
}
/**
* @return a list of all partitions registered via this admin.
*/
Set<String> getPartitions() {
return partitionToInstances.keySet();
}
/**
* @return all writable partitions registered via this Helix admin.
*/
Set<String> getWritablePartitions() {
Set<String> healthyWritablePartitions = new HashSet<>();
for (Map.Entry<String, Set<String>> entry : partitionToInstances.entrySet()) {
if (partitionToPartitionStates.get(entry.getKey()).equals(PartitionState.READ_WRITE)) {
boolean up = true;
for (String instance : entry.getValue()) {
if (!getUpInstances().contains(instance)) {
up = false;
break;
}
}
if (up) {
healthyWritablePartitions.add(entry.getKey());
}
}
}
return healthyWritablePartitions;
}
/**
* @return all writable partitions registered via this Helix admin.
*/
Set<String> getAllWritablePartitions() {
Set<String> writablePartitions = new HashSet<>();
for (Map.Entry<String, Set<String>> entry : partitionToInstances.entrySet()) {
if (partitionToPartitionStates.get(entry.getKey()).equals(PartitionState.READ_WRITE)) {
writablePartitions.add(entry.getKey());
}
}
return writablePartitions;
}
/**
* @return the count of disks registered via this admin.
*/
long getTotalDiskCount() {
return totalDiskCount;
}
/**
* @param instanceName the instance on which this operation is being done.
* @return the count of disks registered for the given node via this admin.
*/
long getDiskCountOnNode(String instanceName) {
InstanceConfig instanceConfig = instanceNameToinstanceConfigs.get(instanceName);
return instanceConfig.getRecord().getMapFields().size();
}
/**
* @return the total capacity across all disks on all nodes registered via this admin.
*/
long getTotalDiskCapacity() {
return totalDiskCapacity;
}
// ***************************************
// Not implemented. Implement as required.
// ***************************************
@Override
public List<String> getResourcesInClusterWithTag(String clusterName, String tag) {
throw new IllegalStateException("Not implemented");
}
@Override
public boolean addCluster(String clusterName, boolean recreateIfExists) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addClusterToGrandCluster(String clusterName, String grandCluster) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addResource(String clusterName, String resourceName, int numPartitions, String stateModelRef) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addResource(String clusterName, String resourceName, int numPartitions, String stateModelRef,
String rebalancerMode) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addResource(String clusterName, String resourceName, int numPartitions, String stateModelRef,
String rebalancerMode, String rebalanceStrategy) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addResource(String clusterName, String resourceName, int numPartitions, String stateModelRef,
String rebalancerMode, int bucketSize) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addResource(String clusterName, String resourceName, int numPartitions, String stateModelRef,
String rebalancerMode, int bucketSize, int maxPartitionsPerInstance) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addResource(String clusterName, String resourceName, int numPartitions, String stateModelRef,
String rebalancerMode, String rebalanceStrategy, int bucketSize, int maxPartitionsPerInstance) {
throw new IllegalStateException("Not implemented");
}
@Override
public void dropInstance(String clusterName, InstanceConfig instanceConfig) {
throw new IllegalStateException("Not implemented");
}
@Override
public void setResourceIdealState(String clusterName, String resourceName, IdealState idealState) {
throw new IllegalStateException("Not implemented");
}
@Override
public void enableInstance(String clusterName, String instanceName, boolean enabled) {
throw new IllegalStateException("Not implemented");
}
@Override
public void enableResource(String clusterName, String resourceName, boolean enabled) {
throw new IllegalStateException("Not implemented");
}
@Override
public void enablePartition(boolean enabled, String clusterName, String instanceName, String resourceName,
List<String> partitionNames) {
throw new IllegalStateException("Not implemented");
}
@Override
public void enableCluster(String clusterName, boolean enabled) {
throw new IllegalStateException("Not implemented");
}
@Override
public void resetPartition(String clusterName, String instanceName, String resourceName,
List<String> partitionNames) {
throw new IllegalStateException("Not implemented");
}
@Override
public void resetInstance(String clusterName, List<String> instanceNames) {
throw new IllegalStateException("Not implemented");
}
@Override
public void resetResource(String clusterName, List<String> resourceNames) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addStateModelDef(String clusterName, String stateModelDef, StateModelDefinition record,
boolean recreateIfExists) {
throw new IllegalStateException("Not implemented");
}
@Override
public void dropResource(String clusterName, String resourceName) {
throw new IllegalStateException("Not implemented");
}
@Override
public List<String> getStateModelDefs(String clusterName) {
throw new IllegalStateException("Not implemented");
}
@Override
public StateModelDefinition getStateModelDef(String clusterName, String stateModelName) {
throw new IllegalStateException("Not implemented");
}
@Override
public ExternalView getResourceExternalView(String clusterName, String resourceName) {
throw new IllegalStateException("Not implemented");
}
@Override
public void dropCluster(String clusterName) {
throw new IllegalStateException("Not implemented");
}
@Override
public void setConfig(HelixConfigScope scope, Map<String, String> properties) {
throw new IllegalStateException("Not implemented");
}
@Override
public void removeConfig(HelixConfigScope scope, List<String> keys) {
throw new IllegalStateException("Not implemented");
}
@Override
public Map<String, String> getConfig(HelixConfigScope scope, List<String> keys) {
throw new IllegalStateException("Not implemented");
}
@Override
public List<String> getConfigKeys(HelixConfigScope scope) {
throw new IllegalStateException("Not implemented");
}
@Override
public void rebalance(String clusterName, String resourceName, int replica) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addIdealState(String clusterName, String resourceName, String idealStateFile) throws IOException {
throw new IllegalStateException("Not implemented");
}
@Override
public void addStateModelDef(String clusterName, String stateModelDefName, String stateModelDefFile)
throws IOException {
throw new IllegalStateException("Not implemented");
}
@Override
public void setConstraint(String clusterName, ClusterConstraints.ConstraintType constraintType, String constraintId,
ConstraintItem constraintItem) {
throw new IllegalStateException("Not implemented");
}
@Override
public void removeConstraint(String clusterName, ClusterConstraints.ConstraintType constraintType,
String constraintId) {
throw new IllegalStateException("Not implemented");
}
@Override
public ClusterConstraints getConstraints(String clusterName, ClusterConstraints.ConstraintType constraintType) {
throw new IllegalStateException("Not implemented");
}
@Override
public void rebalance(String clusterName, IdealState currentIdealState, List<String> instanceNames) {
throw new IllegalStateException("Not implemented");
}
@Override
public void rebalance(String clusterName, String resourceName, int replica, List<String> instances) {
throw new IllegalStateException("Not implemented");
}
@Override
public void rebalance(String clusterName, String resourceName, int replica, String keyPrefix, String group) {
throw new IllegalStateException("Not implemented");
}
@Override
public List<String> getInstancesInClusterWithTag(String clusterName, String tag) {
throw new IllegalStateException("Not implemented");
}
@Override
public void addInstanceTag(String clusterName, String instanceName, String tag) {
throw new IllegalStateException("Not implemented");
}
@Override
public void removeInstanceTag(String clusterName, String instanceName, String tag) {
throw new IllegalStateException("Not implemented");
}
@Override
public void setInstanceZoneId(String clusterName, String instanceName, String zoneId) {
throw new IllegalStateException("Not implemented");
}
@Override
public void close() {
// no-op.
}
}