001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.master.balancer; 019 020import static org.junit.jupiter.api.Assertions.assertTrue; 021import static org.mockito.Mockito.mock; 022import static org.mockito.Mockito.when; 023 024import java.util.Arrays; 025import java.util.List; 026import java.util.Map; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.ServerName; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.client.LogEntry; 031import org.apache.hadoop.hbase.client.RegionInfo; 032import org.apache.hadoop.hbase.master.MasterServices; 033import org.apache.hadoop.hbase.master.RegionPlan; 034import org.apache.hadoop.hbase.namequeues.BalancerDecisionDetails; 035import org.apache.hadoop.hbase.namequeues.request.NamedQueueGetRequest; 036import org.apache.hadoop.hbase.namequeues.response.NamedQueueGetResponse; 037import org.apache.hadoop.hbase.testclassification.MasterTests; 038import org.apache.hadoop.hbase.testclassification.MediumTests; 039import org.junit.jupiter.api.Tag; 040import org.junit.jupiter.api.Test; 041 042import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 043import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos; 044import org.apache.hadoop.hbase.shaded.protobuf.generated.RecentLogs; 045 046/** 047 * Test BalancerDecision ring buffer using namedQueue interface 048 */ 049@Tag(MasterTests.TAG) 050@Tag(MediumTests.TAG) 051public class TestBalancerDecision extends StochasticBalancerTestBase { 052 053 @Test 054 public void testBalancerDecisions() { 055 conf.setBoolean("hbase.master.balancer.decision.buffer.enabled", true); 056 MasterServices services = mock(MasterServices.class); 057 when(services.getConfiguration()).thenReturn(conf); 058 MasterClusterInfoProvider provider = new MasterClusterInfoProvider(services); 059 loadBalancer.setClusterInfoProvider(provider); 060 loadBalancer.onConfigurationChange(conf); 061 float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.05f); 062 float slop = conf.getFloat(HConstants.LOAD_BALANCER_SLOP_KEY, 0.2f); 063 conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f); 064 conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, -1f); 065 try { 066 // Test with/without per table balancer. 067 boolean[] perTableBalancerConfigs = { true, false }; 068 for (boolean isByTable : perTableBalancerConfigs) { 069 conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, isByTable); 070 loadBalancer.onConfigurationChange(conf); 071 for (int[] mockCluster : clusterStateMocks) { 072 Map<ServerName, List<RegionInfo>> servers = mockClusterServers(mockCluster); 073 Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable = 074 (Map) mockClusterServersWithTables(servers); 075 List<RegionPlan> plans = loadBalancer.balanceCluster(LoadOfAllTable); 076 boolean emptyPlans = plans == null || plans.isEmpty(); 077 assertTrue(emptyPlans || needsBalanceIdleRegion(mockCluster)); 078 } 079 } 080 final NamedQueueGetRequest namedQueueGetRequest = new NamedQueueGetRequest(); 081 namedQueueGetRequest.setNamedQueueEvent(BalancerDecisionDetails.BALANCER_DECISION_EVENT); 082 namedQueueGetRequest 083 .setBalancerDecisionsRequest(MasterProtos.BalancerDecisionsRequest.getDefaultInstance()); 084 NamedQueueGetResponse namedQueueGetResponse = 085 provider.getNamedQueueRecorder().getNamedQueueRecords(namedQueueGetRequest); 086 List<RecentLogs.BalancerDecision> balancerDecisions = 087 namedQueueGetResponse.getBalancerDecisions(); 088 MasterProtos.BalancerDecisionsResponse response = MasterProtos.BalancerDecisionsResponse 089 .newBuilder().addAllBalancerDecision(balancerDecisions).build(); 090 List<LogEntry> balancerDecisionRecords = ProtobufUtil.getBalancerDecisionEntries(response); 091 assertTrue(balancerDecisionRecords.size() > 160); 092 } finally { 093 // reset config 094 conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE); 095 conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost); 096 conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, slop); 097 loadBalancer.onConfigurationChange(conf); 098 } 099 } 100 101 private static boolean needsBalanceIdleRegion(int[] cluster) { 102 return (Arrays.stream(cluster).anyMatch(x -> x > 1)) 103 && (Arrays.stream(cluster).anyMatch(x -> x < 1)); 104 } 105}