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.Assert.assertNotNull;
021import static org.junit.Assert.assertNull;
022
023import java.util.List;
024import java.util.Map;
025import org.apache.hadoop.hbase.HBaseConfiguration;
026import org.apache.hadoop.hbase.ServerName;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.client.RegionInfo;
029import org.apache.hadoop.hbase.master.RackManager;
030import org.apache.hadoop.hbase.master.RegionPlan;
031import org.apache.hadoop.net.DNSToSwitchMapping;
032import org.junit.BeforeClass;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036public class StochasticBalancerTestBase extends BalancerTestBase {
037
038  private static final Logger LOG = LoggerFactory.getLogger(StochasticBalancerTestBase.class);
039
040  protected static StochasticLoadBalancer loadBalancer;
041
042  protected static DummyMetricsStochasticBalancer dummyMetricsStochasticBalancer =
043    new DummyMetricsStochasticBalancer();
044
045  @BeforeClass
046  public static void beforeAllTests() throws Exception {
047    conf = HBaseConfiguration.create();
048    conf.setClass("hbase.util.ip.to.rack.determiner", MockMapping.class, DNSToSwitchMapping.class);
049    conf.setFloat("hbase.master.balancer.stochastic.localityCost", 0);
050    conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", true);
051    loadBalancer = new StochasticLoadBalancer(dummyMetricsStochasticBalancer);
052    loadBalancer.setClusterInfoProvider(new DummyClusterInfoProvider(conf));
053    loadBalancer.initialize();
054  }
055
056  protected void testWithCluster(int numNodes, int numRegions, int numRegionsPerServer,
057    int replication, int numTables, boolean assertFullyBalanced,
058    boolean assertFullyBalancedForReplicas) {
059    Map<ServerName, List<RegionInfo>> serverMap =
060      createServerMap(numNodes, numRegions, numRegionsPerServer, replication, numTables);
061    testWithCluster(serverMap, null, assertFullyBalanced, assertFullyBalancedForReplicas);
062  }
063
064  protected void testWithClusterWithIteration(int numNodes, int numRegions, int numRegionsPerServer,
065    int replication, int numTables, boolean assertFullyBalanced,
066    boolean assertFullyBalancedForReplicas) {
067    Map<ServerName, List<RegionInfo>> serverMap =
068      createServerMap(numNodes, numRegions, numRegionsPerServer, replication, numTables);
069    testWithClusterWithIteration(serverMap, null, assertFullyBalanced,
070      assertFullyBalancedForReplicas);
071  }
072
073  protected void testWithCluster(Map<ServerName, List<RegionInfo>> serverMap,
074    RackManager rackManager, boolean assertFullyBalanced, boolean assertFullyBalancedForReplicas) {
075    List<ServerAndLoad> list = convertToList(serverMap);
076    LOG.info("Mock Cluster : " + printMock(list) + " " + printStats(list));
077
078    loadBalancer.setRackManager(rackManager);
079    // Run the balancer.
080    Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable =
081      (Map) mockClusterServersWithTables(serverMap);
082    List<RegionPlan> plans = loadBalancer.balanceCluster(LoadOfAllTable);
083    assertNotNull("Initial cluster balance should produce plans.", plans);
084
085    // Check to see that this actually got to a stable place.
086    if (assertFullyBalanced || assertFullyBalancedForReplicas) {
087      // Apply the plan to the mock cluster.
088      List<ServerAndLoad> balancedCluster = reconcile(list, plans, serverMap);
089
090      // Print out the cluster loads to make debugging easier.
091      LOG.info("Mock after Balance : " + printMock(balancedCluster));
092
093      if (assertFullyBalanced) {
094        assertClusterAsBalanced(balancedCluster);
095        LoadOfAllTable = (Map) mockClusterServersWithTables(serverMap);
096        List<RegionPlan> secondPlans = loadBalancer.balanceCluster(LoadOfAllTable);
097        assertNull("Given a requirement to be fully balanced, second attempt at plans should "
098          + "produce none.", secondPlans);
099      }
100
101      if (assertFullyBalancedForReplicas) {
102        assertRegionReplicaPlacement(serverMap, rackManager);
103      }
104    }
105  }
106
107  protected void testWithClusterWithIteration(Map<ServerName, List<RegionInfo>> serverMap,
108    RackManager rackManager, boolean assertFullyBalanced, boolean assertFullyBalancedForReplicas) {
109    List<ServerAndLoad> list = convertToList(serverMap);
110    LOG.info("Mock Cluster : " + printMock(list) + " " + printStats(list));
111
112    loadBalancer.setRackManager(rackManager);
113    // Run the balancer.
114    Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable =
115      (Map) mockClusterServersWithTables(serverMap);
116    List<RegionPlan> plans = loadBalancer.balanceCluster(LoadOfAllTable);
117    assertNotNull("Initial cluster balance should produce plans.", plans);
118
119    List<ServerAndLoad> balancedCluster = null;
120    // Run through iteration until done. Otherwise will be killed as test time out
121    while (plans != null && (assertFullyBalanced || assertFullyBalancedForReplicas)) {
122      // Apply the plan to the mock cluster.
123      balancedCluster = reconcile(list, plans, serverMap);
124
125      // Print out the cluster loads to make debugging easier.
126      LOG.info("Mock after balance: " + printMock(balancedCluster));
127
128      LoadOfAllTable = (Map) mockClusterServersWithTables(serverMap);
129      plans = loadBalancer.balanceCluster(LoadOfAllTable);
130    }
131
132    // Print out the cluster loads to make debugging easier.
133    LOG.info("Mock Final balance: " + printMock(balancedCluster));
134
135    if (assertFullyBalanced) {
136      assertNull("Given a requirement to be fully balanced, second attempt at plans should "
137        + "produce none.", plans);
138    }
139    if (assertFullyBalancedForReplicas) {
140      assertRegionReplicaPlacement(serverMap, rackManager);
141    }
142  }
143}