| /* |
| * 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. |
| */ |
| package org.apache.hadoop.hbase.master; |
| |
| 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.junit.Assert.fail; |
| |
| import java.io.IOException; |
| import java.net.InetSocketAddress; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Random; |
| import java.util.concurrent.ThreadLocalRandom; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.hbase.CatalogFamilyFormat; |
| import org.apache.hadoop.hbase.ClientMetaTableAccessor; |
| import org.apache.hadoop.hbase.HBaseClassTestRule; |
| import org.apache.hadoop.hbase.HBaseTestingUtil; |
| import org.apache.hadoop.hbase.HConstants; |
| import org.apache.hadoop.hbase.HRegionLocation; |
| import org.apache.hadoop.hbase.MetaTableAccessor; |
| import org.apache.hadoop.hbase.NamespaceDescriptor; |
| import org.apache.hadoop.hbase.ServerName; |
| import org.apache.hadoop.hbase.SingleProcessHBaseCluster; |
| import org.apache.hadoop.hbase.TableName; |
| import org.apache.hadoop.hbase.client.Admin; |
| import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; |
| import org.apache.hadoop.hbase.client.Connection; |
| import org.apache.hadoop.hbase.client.RegionInfo; |
| import org.apache.hadoop.hbase.client.RegionLocator; |
| import org.apache.hadoop.hbase.client.Result; |
| import org.apache.hadoop.hbase.client.TableDescriptor; |
| import org.apache.hadoop.hbase.client.TableDescriptorBuilder; |
| import org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper; |
| import org.apache.hadoop.hbase.favored.FavoredNodeLoadBalancer; |
| import org.apache.hadoop.hbase.favored.FavoredNodesPlan; |
| import org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position; |
| import org.apache.hadoop.hbase.regionserver.HRegion; |
| import org.apache.hadoop.hbase.regionserver.HRegionServer; |
| import org.apache.hadoop.hbase.regionserver.Region; |
| import org.apache.hadoop.hbase.testclassification.MasterTests; |
| import org.apache.hadoop.hbase.testclassification.MediumTests; |
| import org.apache.hadoop.hbase.util.Bytes; |
| import org.apache.hadoop.hbase.util.Pair; |
| import org.apache.zookeeper.KeeperException; |
| import org.junit.AfterClass; |
| import org.junit.BeforeClass; |
| import org.junit.ClassRule; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| @Category({ MasterTests.class, MediumTests.class }) |
| public class TestRegionPlacement { |
| |
| @ClassRule |
| public static final HBaseClassTestRule CLASS_RULE = |
| HBaseClassTestRule.forClass(TestRegionPlacement.class); |
| |
| private static final Logger LOG = LoggerFactory.getLogger(TestRegionPlacement.class); |
| private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); |
| private final static int SLAVES = 10; |
| private static Connection CONNECTION; |
| private static Admin admin; |
| private static RegionPlacementMaintainer rp; |
| private static Position[] positions = Position.values(); |
| private int lastRegionOnPrimaryRSCount = 0; |
| private int REGION_NUM = 10; |
| private Map<RegionInfo, ServerName[]> favoredNodesAssignmentPlan = new HashMap<>(); |
| |
| @BeforeClass |
| public static void setupBeforeClass() throws Exception { |
| Configuration conf = TEST_UTIL.getConfiguration(); |
| // Enable the favored nodes based load balancer |
| conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, FavoredNodeLoadBalancer.class, |
| LoadBalancer.class); |
| conf.setBoolean("hbase.tests.use.shortcircuit.reads", false); |
| TEST_UTIL.startMiniCluster(SLAVES); |
| CONNECTION = TEST_UTIL.getConnection(); |
| admin = CONNECTION.getAdmin(); |
| rp = new RegionPlacementMaintainer(conf); |
| } |
| |
| @AfterClass |
| public static void tearDownAfterClass() throws Exception { |
| TEST_UTIL.shutdownMiniCluster(); |
| } |
| |
| @Ignore("Test for unfinished feature") |
| @Test |
| public void testRegionPlacement() throws Exception { |
| String tableStr = "testRegionAssignment"; |
| TableName table = TableName.valueOf(tableStr); |
| // Create a table with REGION_NUM regions. |
| createTable(table, REGION_NUM); |
| |
| TEST_UTIL.waitTableAvailable(table); |
| |
| // Verify all the user regions are assigned to the primary region server |
| // based on the plan |
| verifyRegionOnPrimaryRS(REGION_NUM); |
| |
| FavoredNodesPlan currentPlan = rp.getRegionAssignmentSnapshot().getExistingAssignmentPlan(); |
| // Verify all the region server are update with the latest favored nodes |
| verifyRegionServerUpdated(currentPlan); |
| // Test Case 2: To verify whether the region placement tools can |
| // correctly update the new assignment plan to hbase:meta and Region Server. |
| // The new assignment plan is generated by shuffle the existing assignment |
| // plan by switching PRIMARY, SECONDARY and TERTIARY nodes. |
| // Shuffle the plan by switching the secondary region server with |
| // the tertiary. |
| |
| // Shuffle the secondary with tertiary favored nodes |
| FavoredNodesPlan shuffledPlan = this.shuffleAssignmentPlan(currentPlan, |
| FavoredNodesPlan.Position.SECONDARY, FavoredNodesPlan.Position.TERTIARY); |
| // Let the region placement update the hbase:meta and Region Servers |
| rp.updateAssignmentPlan(shuffledPlan); |
| |
| // Verify the region assignment. There are supposed to no region reassignment |
| // All the regions are still on the primary region server |
| verifyRegionAssignment(shuffledPlan, 0, REGION_NUM); |
| |
| // Shuffle the plan by switching the primary with secondary and |
| // verify the region reassignment is consistent with the plan. |
| shuffledPlan = this.shuffleAssignmentPlan(currentPlan, FavoredNodesPlan.Position.PRIMARY, |
| FavoredNodesPlan.Position.SECONDARY); |
| |
| // Let the region placement update the hbase:meta and Region Servers |
| rp.updateAssignmentPlan(shuffledPlan); |
| |
| verifyRegionAssignment(shuffledPlan, REGION_NUM, REGION_NUM); |
| |
| // also verify that the AssignmentVerificationReport has the correct information |
| RegionPlacementMaintainer rp = new RegionPlacementMaintainer(TEST_UTIL.getConfiguration()); |
| // we are interested in only one table (and hence one report) |
| rp.setTargetTableName(new String[] { tableStr }); |
| List<AssignmentVerificationReport> reports = rp.verifyRegionPlacement(false); |
| AssignmentVerificationReport report = reports.get(0); |
| assertTrue(report.getRegionsWithoutValidFavoredNodes().isEmpty()); |
| assertTrue(report.getNonFavoredAssignedRegions().isEmpty()); |
| assertTrue(report.getTotalFavoredAssignments() >= REGION_NUM); |
| assertTrue(report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.PRIMARY) != 0); |
| assertTrue( |
| report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.SECONDARY) == 0); |
| assertTrue( |
| report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.TERTIARY) == 0); |
| assertTrue(report.getUnassignedRegions().isEmpty()); |
| |
| // Check when a RS stops, the regions get assigned to their secondary/tertiary |
| killRandomServerAndVerifyAssignment(); |
| |
| // also verify that the AssignmentVerificationReport has the correct information |
| reports = rp.verifyRegionPlacement(false); |
| report = reports.get(0); |
| assertTrue(report.getRegionsWithoutValidFavoredNodes().isEmpty()); |
| assertTrue(report.getNonFavoredAssignedRegions().isEmpty()); |
| assertTrue(report.getTotalFavoredAssignments() >= REGION_NUM); |
| assertTrue(report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.PRIMARY) > 0); |
| assertTrue( |
| "secondary " |
| + report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.SECONDARY) |
| + " tertiary " |
| + report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.TERTIARY), |
| (report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.SECONDARY) > 0 |
| || report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.TERTIARY) > 0)); |
| assertTrue((report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.PRIMARY) |
| + report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.SECONDARY) |
| + report.getNumRegionsOnFavoredNodeByPosition(FavoredNodesPlan.Position.TERTIARY)) |
| == REGION_NUM); |
| RegionPlacementMaintainer.printAssignmentPlan(currentPlan); |
| } |
| |
| private void killRandomServerAndVerifyAssignment() |
| throws IOException, InterruptedException, KeeperException { |
| ServerName serverToKill = null; |
| int killIndex = 0; |
| Random rand = ThreadLocalRandom.current(); |
| ServerName metaServer = TEST_UTIL.getHBaseCluster().getServerHoldingMeta(); |
| LOG.debug("Server holding meta " + metaServer); |
| boolean isNamespaceServer = false; |
| do { |
| // kill a random non-meta server carrying at least one region |
| killIndex = rand.nextInt(SLAVES); |
| serverToKill = TEST_UTIL.getHBaseCluster().getRegionServer(killIndex).getServerName(); |
| Collection<HRegion> regs = |
| TEST_UTIL.getHBaseCluster().getRegionServer(killIndex).getOnlineRegionsLocalContext(); |
| isNamespaceServer = false; |
| for (HRegion r : regs) { |
| if ( |
| r.getRegionInfo().getTable().getNamespaceAsString() |
| .equals(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR) |
| ) { |
| isNamespaceServer = true; |
| break; |
| } |
| } |
| } while ( |
| ServerName.isSameAddress(metaServer, serverToKill) || isNamespaceServer |
| || TEST_UTIL.getHBaseCluster().getRegionServer(killIndex).getNumberOfOnlineRegions() == 0 |
| ); |
| LOG.debug("Stopping RS " + serverToKill); |
| Map<RegionInfo, Pair<ServerName, ServerName>> regionsToVerify = new HashMap<>(); |
| // mark the regions to track |
| for (Map.Entry<RegionInfo, ServerName[]> entry : favoredNodesAssignmentPlan.entrySet()) { |
| ServerName s = entry.getValue()[0]; |
| if (ServerName.isSameAddress(s, serverToKill)) { |
| regionsToVerify.put(entry.getKey(), new Pair<>(entry.getValue()[1], entry.getValue()[2])); |
| LOG.debug("Adding " + entry.getKey() + " with sedcondary/tertiary " + entry.getValue()[1] |
| + " " + entry.getValue()[2]); |
| } |
| } |
| int orig = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().getNumRegionsOpened(); |
| TEST_UTIL.getHBaseCluster().stopRegionServer(serverToKill); |
| TEST_UTIL.getHBaseCluster().waitForRegionServerToStop(serverToKill, 60000); |
| int curr = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().getNumRegionsOpened(); |
| while (curr - orig < regionsToVerify.size()) { |
| LOG.debug("Waiting for " + regionsToVerify.size() + " to come online " + " Current #regions " |
| + curr + " Original #regions " + orig); |
| Thread.sleep(200); |
| curr = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().getNumRegionsOpened(); |
| } |
| // now verify |
| for (Map.Entry<RegionInfo, Pair<ServerName, ServerName>> entry : regionsToVerify.entrySet()) { |
| ServerName newDestination = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager() |
| .getRegionStates().getRegionServerOfRegion(entry.getKey()); |
| Pair<ServerName, ServerName> secondaryTertiaryServers = entry.getValue(); |
| LOG.debug("New destination for region " + entry.getKey().getEncodedName() + " " |
| + newDestination + ". Secondary/Tertiary are " + secondaryTertiaryServers.getFirst() + "/" |
| + secondaryTertiaryServers.getSecond()); |
| if ( |
| !(ServerName.isSameAddress(newDestination, secondaryTertiaryServers.getFirst()) |
| || ServerName.isSameAddress(newDestination, secondaryTertiaryServers.getSecond())) |
| ) { |
| fail("Region " + entry.getKey() + " not present on any of the expected servers"); |
| } |
| } |
| // start(reinstate) region server since we killed one before |
| TEST_UTIL.getHBaseCluster().startRegionServer(); |
| } |
| |
| /** |
| * Used to test the correctness of this class. |
| */ |
| @Ignore("Test for unfinished feature") |
| @Test |
| public void testRandomizedMatrix() { |
| int rows = 100; |
| int cols = 100; |
| float[][] matrix = new float[rows][cols]; |
| Random rand = ThreadLocalRandom.current(); |
| for (int i = 0; i < rows; i++) { |
| for (int j = 0; j < cols; j++) { |
| matrix[i][j] = rand.nextFloat(); |
| } |
| } |
| |
| // Test that inverting a transformed matrix gives the original matrix. |
| RegionPlacementMaintainer.RandomizedMatrix rm = |
| new RegionPlacementMaintainer.RandomizedMatrix(rows, cols); |
| float[][] transformed = rm.transform(matrix); |
| float[][] invertedTransformed = rm.invert(transformed); |
| for (int i = 0; i < rows; i++) { |
| for (int j = 0; j < cols; j++) { |
| if (matrix[i][j] != invertedTransformed[i][j]) { |
| throw new RuntimeException(); |
| } |
| } |
| } |
| |
| // Test that the indices on a transformed matrix can be inverted to give |
| // the same values on the original matrix. |
| int[] transformedIndices = new int[rows]; |
| for (int i = 0; i < rows; i++) { |
| transformedIndices[i] = rand.nextInt(cols); |
| } |
| int[] invertedTransformedIndices = rm.invertIndices(transformedIndices); |
| float[] transformedValues = new float[rows]; |
| float[] invertedTransformedValues = new float[rows]; |
| for (int i = 0; i < rows; i++) { |
| transformedValues[i] = transformed[i][transformedIndices[i]]; |
| invertedTransformedValues[i] = matrix[i][invertedTransformedIndices[i]]; |
| } |
| Arrays.sort(transformedValues); |
| Arrays.sort(invertedTransformedValues); |
| if (!Arrays.equals(transformedValues, invertedTransformedValues)) { |
| throw new RuntimeException(); |
| } |
| } |
| |
| /** |
| * Shuffle the assignment plan by switching two favored node positions. |
| * @param plan The assignment plan |
| * @param p1 The first switch position |
| * @param p2 The second switch position |
| * @return the shuffled assignment plan |
| */ |
| private FavoredNodesPlan shuffleAssignmentPlan(FavoredNodesPlan plan, |
| FavoredNodesPlan.Position p1, FavoredNodesPlan.Position p2) throws IOException { |
| FavoredNodesPlan shuffledPlan = new FavoredNodesPlan(); |
| |
| Map<String, RegionInfo> regionToHRegion = |
| rp.getRegionAssignmentSnapshot().getRegionNameToRegionInfoMap(); |
| for (Map.Entry<String, List<ServerName>> entry : plan.getAssignmentMap().entrySet()) { |
| |
| // copy the server list from the original plan |
| List<ServerName> shuffledServerList = new ArrayList<>(); |
| shuffledServerList.addAll(entry.getValue()); |
| |
| // start to shuffle |
| shuffledServerList.set(p1.ordinal(), entry.getValue().get(p2.ordinal())); |
| shuffledServerList.set(p2.ordinal(), entry.getValue().get(p1.ordinal())); |
| |
| // update the plan |
| shuffledPlan.updateFavoredNodesMap(regionToHRegion.get(entry.getKey()), shuffledServerList); |
| } |
| return shuffledPlan; |
| } |
| |
| /** |
| * To verify the region assignment status. It will check the assignment plan consistency between |
| * hbase:meta and region servers. Also it will verify weather the number of region movement and |
| * the number regions on the primary region server are expected |
| */ |
| private void verifyRegionAssignment(FavoredNodesPlan plan, int regionMovementNum, |
| int numRegionsOnPrimaryRS) throws InterruptedException, IOException { |
| // Verify the assignment plan in hbase:meta is consistent with the expected plan. |
| verifyMETAUpdated(plan); |
| |
| // Verify the number of region movement is expected |
| verifyRegionMovementNum(regionMovementNum); |
| |
| // Verify the number of regions is assigned to the primary region server |
| // based on the plan is expected |
| verifyRegionOnPrimaryRS(numRegionsOnPrimaryRS); |
| |
| // Verify all the online region server are updated with the assignment plan |
| verifyRegionServerUpdated(plan); |
| } |
| |
| /** |
| * Verify the meta has updated to the latest assignment plan |
| * @param expectedPlan the region assignment plan |
| * @throws IOException if an IO problem is encountered |
| */ |
| private void verifyMETAUpdated(FavoredNodesPlan expectedPlan) throws IOException { |
| FavoredNodesPlan planFromMETA = rp.getRegionAssignmentSnapshot().getExistingAssignmentPlan(); |
| assertTrue("The assignment plan is NOT consistent with the expected plan ", |
| planFromMETA.equals(expectedPlan)); |
| } |
| |
| /** |
| * Verify the number of region movement is expected |
| */ |
| private void verifyRegionMovementNum(int expected) throws InterruptedException, IOException { |
| SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); |
| HMaster m = cluster.getMaster(); |
| int lastRegionOpenedCount = m.getAssignmentManager().getNumRegionsOpened(); |
| // get the assignments start to execute |
| m.balance(); |
| |
| int retry = 10; |
| long sleep = 3000; |
| int attempt = 0; |
| int currentRegionOpened, regionMovement; |
| do { |
| currentRegionOpened = m.getAssignmentManager().getNumRegionsOpened(); |
| regionMovement = currentRegionOpened - lastRegionOpenedCount; |
| LOG.debug("There are " + regionMovement + "/" + expected + " regions moved after " + attempt |
| + " attempts"); |
| Thread.sleep((++attempt) * sleep); |
| } while (regionMovement != expected && attempt <= retry); |
| |
| // update the lastRegionOpenedCount |
| lastRegionOpenedCount = currentRegionOpened; |
| |
| assertEquals("There are only " + regionMovement + " instead of " + expected |
| + " region movement for " + attempt + " attempts", expected, regionMovement); |
| } |
| |
| /** |
| * Verify the number of user regions is assigned to the primary region server based on the plan is |
| * expected |
| * @param expectedNum the expected number of assigned regions |
| */ |
| private void verifyRegionOnPrimaryRS(int expectedNum) throws IOException { |
| lastRegionOnPrimaryRSCount = getNumRegionisOnPrimaryRS(); |
| assertEquals( |
| "Only " + expectedNum + " of user regions running " + "on the primary region server", |
| expectedNum, lastRegionOnPrimaryRSCount); |
| } |
| |
| /** |
| * Verify all the online region servers has been updated to the latest assignment plan |
| */ |
| private void verifyRegionServerUpdated(FavoredNodesPlan plan) throws IOException { |
| // Verify all region servers contain the correct favored nodes information |
| SingleProcessHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); |
| for (int i = 0; i < SLAVES; i++) { |
| HRegionServer rs = cluster.getRegionServer(i); |
| for (Region region : rs.getRegions(TableName.valueOf("testRegionAssignment"))) { |
| InetSocketAddress[] favoredSocketAddress = |
| rs.getFavoredNodesForRegion(region.getRegionInfo().getEncodedName()); |
| String regionName = region.getRegionInfo().getRegionNameAsString(); |
| List<ServerName> favoredServerList = plan.getAssignmentMap().get(regionName); |
| |
| // All regions are supposed to have favored nodes, |
| // except for hbase:meta and ROOT |
| if (favoredServerList == null) { |
| TableDescriptor desc = region.getTableDescriptor(); |
| // Verify they are ROOT and hbase:meta regions since no favored nodes |
| assertNull(favoredSocketAddress); |
| assertTrue("User region " + region.getTableDescriptor().getTableName() |
| + " should have favored nodes", desc.isMetaRegion()); |
| } else { |
| // For user region, the favored nodes in the region server should be |
| // identical to favored nodes in the assignmentPlan |
| assertTrue(favoredSocketAddress.length == favoredServerList.size()); |
| assertTrue(favoredServerList.size() > 0); |
| for (int j = 0; j < favoredServerList.size(); j++) { |
| InetSocketAddress addrFromRS = favoredSocketAddress[j]; |
| InetSocketAddress addrFromPlan = InetSocketAddress.createUnresolved( |
| favoredServerList.get(j).getHostname(), favoredServerList.get(j).getPort()); |
| |
| assertNotNull(addrFromRS); |
| assertNotNull(addrFromPlan); |
| assertTrue( |
| "Region server " + rs.getServerName().getAddress() + " has the " + positions[j] |
| + " for region " + region.getRegionInfo().getRegionNameAsString() + " is " |
| + addrFromRS + " which is inconsistent with the plan " + addrFromPlan, |
| addrFromRS.equals(addrFromPlan)); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Check whether regions are assigned to servers consistent with the explicit hints that are |
| * persisted in the hbase:meta table. Also keep track of the number of the regions are assigned to |
| * the primary region server. |
| * @return the number of regions are assigned to the primary region server |
| */ |
| private int getNumRegionisOnPrimaryRS() throws IOException { |
| final AtomicInteger regionOnPrimaryNum = new AtomicInteger(0); |
| final AtomicInteger totalRegionNum = new AtomicInteger(0); |
| LOG.info("The start of region placement verification"); |
| ClientMetaTableAccessor.Visitor visitor = new ClientMetaTableAccessor.Visitor() { |
| @Override |
| public boolean visit(Result result) throws IOException { |
| try { |
| @SuppressWarnings("deprecation") |
| RegionInfo info = CatalogFamilyFormat.getRegionInfo(result); |
| if ( |
| info.getTable().getNamespaceAsString() |
| .equals(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR) |
| ) { |
| return true; |
| } |
| byte[] server = result.getValue(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER); |
| byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY, |
| FavoredNodeAssignmentHelper.FAVOREDNODES_QUALIFIER); |
| // Add the favored nodes into assignment plan |
| ServerName[] favoredServerList = |
| FavoredNodeAssignmentHelper.getFavoredNodesList(favoredNodes); |
| favoredNodesAssignmentPlan.put(info, favoredServerList); |
| |
| Position[] positions = Position.values(); |
| if (info != null) { |
| totalRegionNum.incrementAndGet(); |
| if (server != null) { |
| ServerName serverName = ServerName.valueOf(Bytes.toString(server), -1); |
| if (favoredNodes != null) { |
| String placement = "[NOT FAVORED NODE]"; |
| for (int i = 0; i < favoredServerList.length; i++) { |
| if (favoredServerList[i].equals(serverName)) { |
| placement = positions[i].toString(); |
| if (i == Position.PRIMARY.ordinal()) { |
| regionOnPrimaryNum.incrementAndGet(); |
| } |
| break; |
| } |
| } |
| LOG.info(info.getRegionNameAsString() + " on " + serverName + " " + placement); |
| } else { |
| LOG.info(info.getRegionNameAsString() + " running on " + serverName |
| + " but there is no favored region server"); |
| } |
| } else { |
| LOG.info(info.getRegionNameAsString() + " not assigned to any server"); |
| } |
| } |
| return true; |
| } catch (RuntimeException e) { |
| LOG.error("Result=" + result); |
| throw e; |
| } |
| } |
| }; |
| MetaTableAccessor.fullScanRegions(CONNECTION, visitor); |
| LOG.info("There are " + regionOnPrimaryNum.intValue() + " out of " + totalRegionNum.intValue() |
| + " regions running on the primary" + " region servers"); |
| return regionOnPrimaryNum.intValue(); |
| } |
| |
| /** |
| * Create a table with specified table name and region number. |
| * @param tableName the name of the table to be created |
| * @param regionNum number of regions to create |
| */ |
| private static void createTable(TableName tableName, int regionNum) throws IOException { |
| int expectedRegions = regionNum; |
| byte[][] splitKeys = new byte[expectedRegions - 1][]; |
| for (int i = 1; i < expectedRegions; i++) { |
| byte splitKey = (byte) i; |
| splitKeys[i - 1] = new byte[] { splitKey, splitKey, splitKey }; |
| } |
| |
| TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName) |
| .setColumnFamily(ColumnFamilyDescriptorBuilder.of(HConstants.CATALOG_FAMILY)).build(); |
| admin.createTable(tableDescriptor, splitKeys); |
| |
| try (RegionLocator r = CONNECTION.getRegionLocator(tableName)) { |
| List<HRegionLocation> regions = r.getAllRegionLocations(); |
| assertEquals( |
| "Tried to create " + expectedRegions + " regions " + "but only found " + regions.size(), |
| expectedRegions, regions.size()); |
| } |
| } |
| } |