From affaf9ed60d0ca08395ced87f7155464280247b6 Mon Sep 17 00:00:00 2001 From: Elliott Clark Date: Mon, 19 Aug 2013 16:34:35 -0700 Subject: [PATCH] HBASE-9267 Change region load in load balancer to use array. --- .../hbase/master/balancer/BaseLoadBalancer.java | 8 +-- .../master/balancer/StochasticLoadBalancer.java | 40 +++++++++------ .../balancer/TestStochasticLoadBalancer.java | 54 +++++++++++++++++--- 3 files changed, 75 insertions(+), 27 deletions(-) diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java index 0b50627..e161455 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java @@ -61,7 +61,7 @@ public abstract class BaseLoadBalancer implements LoadBalancer { ServerName[] servers; ArrayList tables; HRegionInfo[] regions; - List[] regionLoads; + RegionLoad[][] regionLoads; int[][] regionLocations; //regionIndex -> list of serverIndex sorted by locality int[][] regionsPerServer; //serverIndex -> region list @@ -83,7 +83,7 @@ public abstract class BaseLoadBalancer implements LoadBalancer { int numMovedRegions = 0; //num moved regions from the initial configuration int numMovedMetaRegions = 0; //num of moved regions that are META - protected Cluster(Map> clusterState, Map> loads, + protected Cluster(Map> clusterState, Map loads, RegionLocationFinder regionFinder) { serversToIndex = new HashMap(); @@ -119,7 +119,7 @@ public abstract class BaseLoadBalancer implements LoadBalancer { regionIndexToServerIndex = new int[numRegions]; initialRegionIndexToServerIndex = new int[numRegions]; regionIndexToTableIndex = new int[numRegions]; - regionLoads = new List[numRegions]; + regionLoads = new RegionLoad[numRegions][]; regionLocations = new int[numRegions][]; serverIndicesSortedByRegionCount = new Integer[numServers]; @@ -160,7 +160,7 @@ public abstract class BaseLoadBalancer implements LoadBalancer { // region load if (loads != null) { - List rl = loads.get(region.getRegionNameAsString()); + RegionLoad[] rl = loads.get(region.getRegionNameAsString()); // That could have failed if the RegionLoad is using the other regionName if (rl == null) { // Try getting the region load using encoded name. diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java index cd4f3cb..a3bdbba 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java @@ -17,7 +17,6 @@ */ package org.apache.hadoop.hbase.master.balancer; -import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -25,6 +24,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Random; +import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.math.stat.descriptive.DescriptiveStatistics; @@ -101,7 +101,8 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { private final RegionLocationFinder regionFinder = new RegionLocationFinder(); private ClusterStatus clusterStatus = null; - private Map> loads = new HashMap>(); + + Map loads = new HashMap(); // values are defaults private int maxSteps = 1000000; @@ -303,8 +304,8 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { private synchronized void updateRegionLoad() { // We create a new hashmap so that regions that are no longer there are removed. // However we temporarily need the old loads so we can use them to keep the rolling average. - Map> oldLoads = loads; - loads = new HashMap>(); + Map oldLoads = loads; + loads = new HashMap(); for (ServerName sn : clusterStatus.getServers()) { ServerLoad sl = clusterStatus.getLoad(sn); @@ -312,19 +313,21 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { continue; } for (Entry entry : sl.getRegionsLoad().entrySet()) { - List rLoads = oldLoads.get(Bytes.toString(entry.getKey())); + RegionLoad[] rLoads = oldLoads.get(Bytes.toString(entry.getKey())); if (rLoads != null) { + int index = ArrayUtils.indexOf(rLoads, null); // We're only going to keep 15. So if there are that many already take the last 14 - if (rLoads.size() >= numRegionLoadsToRemember) { - int numToRemove = 1 + (rLoads.size() - numRegionLoadsToRemember); - rLoads = rLoads.subList(numToRemove, rLoads.size()); + if (index == ArrayUtils.INDEX_NOT_FOUND) { + System.arraycopy(rLoads, 1, rLoads, 0, rLoads.length - 1); + rLoads[rLoads.length-1] = null; } } else { // There was nothing there - rLoads = new ArrayList(); + rLoads = new RegionLoad[numRegionLoadsToRemember]; } - rLoads.add(entry.getValue()); + int index = ArrayUtils.indexOf(rLoads, null); + rLoads[index] = entry.getValue(); loads.put(Bytes.toString(entry.getKey()), rLoads); } @@ -560,7 +563,7 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { public abstract static class CostFunction { private float multiplier = 0; - private Configuration conf; + protected Configuration conf; CostFunction(Configuration c) { this.conf = c; @@ -806,7 +809,7 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { public abstract static class CostFromRegionLoadFunction extends CostFunction { private ClusterStatus clusterStatus = null; - private Map> loads = null; + private Map loads = null; private double[] stats = null; CostFromRegionLoadFunction(Configuration conf) { super(conf); @@ -816,7 +819,7 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { this.clusterStatus = status; } - void setLoads(Map> l) { + void setLoads(Map l) { this.loads = l; } @@ -836,7 +839,7 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { // for every region on this server get the rl for(int regionIndex:cluster.regionsPerServer[i]) { - List regionLoadList = cluster.regionLoads[regionIndex]; + RegionLoad[] regionLoadList = cluster.regionLoads[regionIndex]; // Now if we found a region load get the type of cost that was requested. if (regionLoadList != null) { @@ -852,10 +855,17 @@ public class StochasticLoadBalancer extends BaseLoadBalancer { return costFromArray(stats); } - protected double getRegionLoadCost(List regionLoadList) { + protected double getRegionLoadCost(RegionLoad[] regionLoadList) { double cost = 0; for (RegionLoad rl : regionLoadList) { + /** + * Make sure there are no nulls. + */ + if (rl == null) { + continue; + } + double toAdd = getCostFromRl(rl); if (cost == 0) { diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java index d3c54d8..8832a43 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java @@ -17,32 +17,38 @@ */ package org.apache.hadoop.hbase.master.balancer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - import java.util.ArrayList; -import java.util.HashMap; +import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.TreeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.math.stat.descriptive.DescriptiveStatistics; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.ClusterStatus; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.MediumTests; +import org.apache.hadoop.hbase.RegionLoad; +import org.apache.hadoop.hbase.ServerLoad; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.master.RegionPlan; +import org.apache.hadoop.hbase.util.Bytes; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + @Category(MediumTests.class) public class TestStochasticLoadBalancer extends BalancerTestBase { + public static final String REGION_KEY = "testRegion"; private static StochasticLoadBalancer loadBalancer; private static final Log LOG = LogFactory.getLog(TestStochasticLoadBalancer.class); @@ -111,6 +117,38 @@ public class TestStochasticLoadBalancer extends BalancerTestBase { new int[]{130, 140, 60, 100, 100, 100, 80, 100} }; + @Test + public void testKeepRegionLoad() throws Exception { + + ServerName sn = new ServerName("test:8080", 100); + int numClusterStatusToAdd = 200; + for (int i = 0; i < numClusterStatusToAdd; i++) { + ServerLoad sl = mock(ServerLoad.class); + + RegionLoad rl = mock(RegionLoad.class); + when(rl.getStores()).thenReturn(i); + + Map regionLoadMap = + new TreeMap(Bytes.BYTES_COMPARATOR); + regionLoadMap.put(Bytes.toBytes(REGION_KEY), rl); + when(sl.getRegionsLoad()).thenReturn(regionLoadMap); + + ClusterStatus clusterStatus = mock(ClusterStatus.class); + when(clusterStatus.getServers()).thenReturn(Arrays.asList(sn)); + when(clusterStatus.getLoad(sn)).thenReturn(sl); + + loadBalancer.setClusterStatus(clusterStatus); + } + assertTrue(loadBalancer.loads.get(REGION_KEY) != null); + assertTrue(loadBalancer.loads.get(REGION_KEY).length == 15); + + RegionLoad[] loads = loadBalancer.loads.get(REGION_KEY); + for (int i = 0; i < loads.length; i++) { + RegionLoad rl = loads[i]; + assertEquals(i + (numClusterStatusToAdd - 15), rl.getStores()); + } + } + /** * Test the load balancing algorithm. * -- 1.7.10.2 (Apple Git-33)