blob: 2b2b04966083681e51883f730d0fcae5ebd5e837 [file] [log] [blame]
package org.apache.helix.controller.stages;
/*
* 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.
*/
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.apache.helix.api.config.StateTransitionThrottleConfig;
import org.apache.helix.model.ClusterConfig;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.apache.helix.api.config.StateTransitionThrottleConfig.RebalanceType.ANY;
import static org.apache.helix.api.config.StateTransitionThrottleConfig.RebalanceType.LOAD_BALANCE;
import static org.apache.helix.api.config.StateTransitionThrottleConfig.RebalanceType.RECOVERY_BALANCE;
public class TestStateTransitionThrottleController {
private static final String INSTANCE = "instance0";
private static final String RESOURCE = "db0";
private static final List<StateTransitionThrottleConfig.RebalanceType> VALID_REBALANCE_TYPES =
ImmutableList.of(LOAD_BALANCE, RECOVERY_BALANCE, ANY);
@Test(description = "When cluster level ANY throttle config is set")
public void testChargeClusterWhenANYClusterLevelThrottleConfig() {
int maxNumberOfST = 1;
ClusterConfig clusterConfig = new ClusterConfig("config");
clusterConfig
.setStateTransitionThrottleConfigs(ImmutableList.of(new StateTransitionThrottleConfig(ANY,
StateTransitionThrottleConfig.ThrottleScope.CLUSTER, maxNumberOfST)));
StateTransitionThrottleControllerAccessor controller =
new StateTransitionThrottleControllerAccessor(RESOURCE, INSTANCE, clusterConfig);
Assert.assertTrue(controller.isThrottleEnabled());
for (StateTransitionThrottleConfig.RebalanceType rebalanceType : VALID_REBALANCE_TYPES) {
controller.chargeCluster(rebalanceType);
for (StateTransitionThrottleConfig.RebalanceType type : VALID_REBALANCE_TYPES) {
Assert.assertTrue(controller.shouldThrottleForCluster(type));
Assert.assertTrue(controller.shouldThrottleForInstance(type, INSTANCE));
Assert.assertTrue(controller.shouldThrottleForInstance(type, RESOURCE));
}
// reset controller
controller = new StateTransitionThrottleControllerAccessor(RESOURCE, INSTANCE, clusterConfig);
}
}
@Test(description = "When cluster throttle is config of LOAD_BALANCE/RECOVERY_BALANCE, no ANY type")
public void testChargeCluster_OnlySetClusterSpecificType() {
int maxNumberOfST = 1;
ClusterConfig clusterConfig = new ClusterConfig("config");
clusterConfig.setStateTransitionThrottleConfigs(ImmutableList.of(
new StateTransitionThrottleConfig(RECOVERY_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.CLUSTER, maxNumberOfST),
new StateTransitionThrottleConfig(LOAD_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.CLUSTER, maxNumberOfST)));
StateTransitionThrottleControllerAccessor controller =
new StateTransitionThrottleControllerAccessor(RESOURCE, INSTANCE, clusterConfig);
Assert.assertTrue(controller.isThrottleEnabled());
controller.chargeCluster(ANY);
Assert.assertEquals(controller.getClusterLevelQuota(RECOVERY_BALANCE), 1);
Assert.assertEquals(controller.getClusterLevelQuota(LOAD_BALANCE), 1);
Assert.assertEquals(controller.getClusterLevelQuota(ANY), 0);
VALID_REBALANCE_TYPES.forEach(controller::chargeCluster);
for (StateTransitionThrottleConfig.RebalanceType rebalanceType : ImmutableList.of(LOAD_BALANCE,
RECOVERY_BALANCE)) {
Assert.assertTrue(controller.shouldThrottleForCluster(rebalanceType));
Assert.assertTrue(controller.shouldThrottleForInstance(rebalanceType, INSTANCE));
Assert.assertTrue(controller.shouldThrottleForResource(rebalanceType, RESOURCE));
}
}
@DataProvider
public static Object[][] mixedConfigurations() {
// TODO: add more mixed configuration setting when refactoring the controller logic
return new Object[][] {
{
10, 9, 8, 7, 6, 5, 4, 3, 2
}
};
}
@Test(dataProvider = "mixedConfigurations")
public void testChargeClusterWithMixedThrottleConfig(int anyClusterLevelQuota,
int loadClusterLevelQuota, int recoveryClusterLevelQuota, int anyInstanceLevelQuota,
int loadInstanceLevelQuota, int recoveryInstanceLevelQuota, int anyResourceLevelQuota,
int loadResourceLevelQuota, int recoveryResourceLevelQuota) {
List<StateTransitionThrottleConfig> stateTransitionThrottleConfigs = Arrays.asList(
new StateTransitionThrottleConfig(ANY, StateTransitionThrottleConfig.ThrottleScope.CLUSTER,
anyClusterLevelQuota),
new StateTransitionThrottleConfig(RECOVERY_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.CLUSTER, recoveryClusterLevelQuota),
new StateTransitionThrottleConfig(LOAD_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.CLUSTER, loadClusterLevelQuota),
new StateTransitionThrottleConfig(ANY, StateTransitionThrottleConfig.ThrottleScope.INSTANCE,
anyInstanceLevelQuota),
new StateTransitionThrottleConfig(RECOVERY_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.INSTANCE, recoveryInstanceLevelQuota),
new StateTransitionThrottleConfig(LOAD_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.INSTANCE, loadInstanceLevelQuota),
new StateTransitionThrottleConfig(ANY, StateTransitionThrottleConfig.ThrottleScope.RESOURCE,
anyResourceLevelQuota),
new StateTransitionThrottleConfig(RECOVERY_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.RESOURCE, recoveryResourceLevelQuota),
new StateTransitionThrottleConfig(LOAD_BALANCE,
StateTransitionThrottleConfig.ThrottleScope.RESOURCE, loadResourceLevelQuota));
ClusterConfig clusterConfig = new ClusterConfig("config");
clusterConfig.setStateTransitionThrottleConfigs(stateTransitionThrottleConfigs);
StateTransitionThrottleControllerAccessor controller =
new StateTransitionThrottleControllerAccessor(RESOURCE, INSTANCE, clusterConfig);
Assert.assertTrue(controller.isThrottleEnabled());
// verify behavior after charging cluster
controller.chargeCluster(ANY);
Assert.assertEquals(controller.getClusterLevelQuota(ANY), anyClusterLevelQuota - 1);
controller.chargeCluster(RECOVERY_BALANCE);
Assert.assertEquals(controller.getClusterLevelQuota(RECOVERY_BALANCE),
recoveryClusterLevelQuota - 1);
controller.chargeCluster(LOAD_BALANCE);
Assert.assertEquals(controller.getClusterLevelQuota(LOAD_BALANCE), loadClusterLevelQuota - 1);
// verify behavior after charging instance
controller.chargeInstance(ANY, INSTANCE);
Assert.assertEquals(controller.getInstanceLevelQuota(ANY, INSTANCE), anyInstanceLevelQuota - 1);
controller.chargeInstance(RECOVERY_BALANCE, INSTANCE);
Assert.assertEquals(controller.getInstanceLevelQuota(RECOVERY_BALANCE, INSTANCE),
recoveryInstanceLevelQuota - 1);
controller.chargeInstance(LOAD_BALANCE, INSTANCE);
Assert.assertEquals(controller.getInstanceLevelQuota(LOAD_BALANCE, INSTANCE),
loadInstanceLevelQuota - 1);
// verify behavior after charging resource
controller.chargeResource(ANY, RESOURCE);
Assert.assertEquals(controller.getResourceLevelQuota(ANY, RESOURCE), anyResourceLevelQuota - 1);
controller.chargeResource(RECOVERY_BALANCE, RESOURCE);
Assert.assertEquals(controller.getResourceLevelQuota(RECOVERY_BALANCE, RESOURCE),
recoveryResourceLevelQuota - 1);
controller.chargeResource(LOAD_BALANCE, RESOURCE);
Assert.assertEquals(controller.getResourceLevelQuota(LOAD_BALANCE, RESOURCE),
loadResourceLevelQuota - 1);
}
// The inner class just to fetch the protected fields of {@link StateTransitionThrottleController}
private static class StateTransitionThrottleControllerAccessor
extends StateTransitionThrottleController {
StateTransitionThrottleControllerAccessor(String resource, String liveInstance,
ClusterConfig clusterConfig) {
super(ImmutableSet.of(resource), clusterConfig, ImmutableSet.of(liveInstance));
}
long getClusterLevelQuota(StateTransitionThrottleConfig.RebalanceType rebalanceType) {
return _pendingTransitionAllowedInCluster.getOrDefault(rebalanceType, 0L);
}
long getResourceLevelQuota(StateTransitionThrottleConfig.RebalanceType rebalanceType,
String resource) {
return _pendingTransitionAllowedPerResource.getOrDefault(resource, Collections.emptyMap())
.getOrDefault(rebalanceType, 0L);
}
long getInstanceLevelQuota(StateTransitionThrottleConfig.RebalanceType rebalanceType,
String instance) {
return _pendingTransitionAllowedPerInstance.getOrDefault(instance, Collections.emptyMap())
.getOrDefault(rebalanceType, 0L);
}
}
}