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.regionserver; 019 020import static org.junit.jupiter.api.Assertions.fail; 021import static org.junit.jupiter.api.Assumptions.assumeTrue; 022 023import java.lang.reflect.Method; 024import java.net.InetSocketAddress; 025import java.net.URI; 026import java.util.ArrayList; 027import java.util.List; 028import org.apache.hadoop.fs.BlockLocation; 029import org.apache.hadoop.fs.FileStatus; 030import org.apache.hadoop.fs.Path; 031import org.apache.hadoop.fs.permission.FsPermission; 032import org.apache.hadoop.hbase.HBaseTestingUtil; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.Table; 035import org.apache.hadoop.hbase.testclassification.MediumTests; 036import org.apache.hadoop.hbase.testclassification.RegionServerTests; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.apache.hadoop.hdfs.DistributedFileSystem; 039import org.apache.hadoop.hdfs.server.datanode.DataNode; 040import org.apache.hadoop.util.Progressable; 041import org.junit.jupiter.api.AfterAll; 042import org.junit.jupiter.api.BeforeAll; 043import org.junit.jupiter.api.Tag; 044import org.junit.jupiter.api.Test; 045 046/** 047 * Tests the ability to specify favored nodes for a region. 048 */ 049@Tag(RegionServerTests.TAG) 050@Tag(MediumTests.TAG) 051public class TestRegionFavoredNodes { 052 053 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 054 private static Table table; 055 private static final TableName TABLE_NAME = TableName.valueOf("table"); 056 private static final byte[] COLUMN_FAMILY = Bytes.toBytes("family"); 057 private static final int FAVORED_NODES_NUM = 3; 058 private static final int REGION_SERVERS = 6; 059 private static final int FLUSHES = 3; 060 private static Method createWithFavoredNode = null; 061 062 @BeforeAll 063 public static void setUpBeforeClass() throws Exception { 064 try { 065 createWithFavoredNode = DistributedFileSystem.class.getDeclaredMethod("create", Path.class, 066 FsPermission.class, boolean.class, int.class, short.class, long.class, Progressable.class, 067 InetSocketAddress[].class); 068 } catch (NoSuchMethodException nm) { 069 return; 070 } 071 TEST_UTIL.startMiniCluster(REGION_SERVERS); 072 table = TEST_UTIL.createMultiRegionTable(TABLE_NAME, COLUMN_FAMILY); 073 TEST_UTIL.waitUntilAllRegionsAssigned(TABLE_NAME); 074 } 075 076 @AfterAll 077 public static void tearDownAfterClass() throws Exception { 078 // guard against failure in setup 079 if (table != null) { 080 table.close(); 081 } 082 if (createWithFavoredNode == null) { 083 return; 084 } 085 TEST_UTIL.shutdownMiniCluster(); 086 } 087 088 @Test 089 public void testFavoredNodes() throws Exception { 090 assumeTrue(createWithFavoredNode != null); 091 // Get the addresses of the datanodes in the cluster. 092 InetSocketAddress[] nodes = new InetSocketAddress[REGION_SERVERS]; 093 List<DataNode> datanodes = TEST_UTIL.getDFSCluster().getDataNodes(); 094 Method selfAddress; 095 try { 096 selfAddress = DataNode.class.getMethod("getSelfAddr"); 097 } catch (NoSuchMethodException ne) { 098 selfAddress = DataNode.class.getMethod("getXferAddress"); 099 } 100 for (int i = 0; i < REGION_SERVERS; i++) { 101 nodes[i] = (InetSocketAddress) selfAddress.invoke(datanodes.get(i)); 102 } 103 104 String[] nodeNames = new String[REGION_SERVERS]; 105 for (int i = 0; i < REGION_SERVERS; i++) { 106 nodeNames[i] = nodes[i].getAddress().getHostAddress() + ":" + nodes[i].getPort(); 107 } 108 109 // For each region, choose some datanodes as the favored nodes then assign 110 // them as favored nodes through the region. 111 for (int i = 0; i < REGION_SERVERS; i++) { 112 HRegionServer server = TEST_UTIL.getHBaseCluster().getRegionServer(i); 113 List<HRegion> regions = server.getRegions(TABLE_NAME); 114 for (HRegion region : regions) { 115 List< 116 org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ServerName> favoredNodes = 117 new ArrayList<>(3); 118 String encodedRegionName = region.getRegionInfo().getEncodedName(); 119 for (int j = 0; j < FAVORED_NODES_NUM; j++) { 120 org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ServerName.Builder b = 121 org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ServerName.newBuilder(); 122 b.setHostName(nodes[(i + j) % REGION_SERVERS].getAddress().getHostAddress()); 123 b.setPort(nodes[(i + j) % REGION_SERVERS].getPort()); 124 b.setStartCode(-1); 125 favoredNodes.add(b.build()); 126 } 127 server.updateRegionFavoredNodesMapping(encodedRegionName, favoredNodes); 128 } 129 } 130 131 // Write some data to each region and flush. Repeat some number of times to 132 // get multiple files for each region. 133 for (int i = 0; i < FLUSHES; i++) { 134 TEST_UTIL.loadTable(table, COLUMN_FAMILY, false); 135 TEST_UTIL.flush(); 136 } 137 138 // For each region, check the block locations of each file and ensure that 139 // they are consistent with the favored nodes for that region. 140 for (int i = 0; i < REGION_SERVERS; i++) { 141 HRegionServer server = TEST_UTIL.getHBaseCluster().getRegionServer(i); 142 List<HRegion> regions = server.getRegions(TABLE_NAME); 143 for (HRegion region : regions) { 144 List<String> files = region.getStoreFileList(new byte[][] { COLUMN_FAMILY }); 145 for (String file : files) { 146 FileStatus status = TEST_UTIL.getDFSCluster().getFileSystem() 147 .getFileStatus(new Path(new URI(file).getPath())); 148 BlockLocation[] lbks = ((DistributedFileSystem) TEST_UTIL.getDFSCluster().getFileSystem()) 149 .getFileBlockLocations(status, 0, Long.MAX_VALUE); 150 for (BlockLocation lbk : lbks) { 151 locations: for (String info : lbk.getNames()) { 152 for (int j = 0; j < FAVORED_NODES_NUM; j++) { 153 if (info.equals(nodeNames[(i + j) % REGION_SERVERS])) { 154 continue locations; 155 } 156 } 157 // This block was at a location that was not a favored location. 158 fail("Block location " + info + " not a favored node"); 159 } 160 } 161 } 162 } 163 } 164 } 165}