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; 019 020import static org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position.PRIMARY; 021import static org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position.SECONDARY; 022import static org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position.TERTIARY; 023 024import java.io.IOException; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032import java.util.TreeMap; 033import org.apache.hadoop.hbase.HConstants; 034import org.apache.hadoop.hbase.HRegionLocation; 035import org.apache.hadoop.hbase.MetaTableAccessor; 036import org.apache.hadoop.hbase.RegionLocations; 037import org.apache.hadoop.hbase.ServerName; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.client.Connection; 040import org.apache.hadoop.hbase.client.RegionInfo; 041import org.apache.hadoop.hbase.client.Result; 042import org.apache.hadoop.hbase.client.ResultScanner; 043import org.apache.hadoop.hbase.client.Table; 044import org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper; 045import org.apache.hadoop.hbase.favored.FavoredNodesPlan; 046import org.apache.yetus.audience.InterfaceAudience; 047import org.slf4j.Logger; 048import org.slf4j.LoggerFactory; 049 050/** 051 * Used internally for reading meta and constructing datastructures that are then queried, for 052 * things like regions to regionservers, table to regions, etc. It also records the favored nodes 053 * mapping for regions. 054 */ 055@InterfaceAudience.Private 056public class SnapshotOfRegionAssignmentFromMeta { 057 private static final Logger LOG = 058 LoggerFactory.getLogger(SnapshotOfRegionAssignmentFromMeta.class.getName()); 059 060 private final Connection connection; 061 062 /** the table name to region map */ 063 private final Map<TableName, List<RegionInfo>> tableToRegionMap; 064 /** the region to region server map */ 065 // private final Map<RegionInfo, ServerName> regionToRegionServerMap; 066 private Map<RegionInfo, ServerName> regionToRegionServerMap; 067 /** the region name to region info map */ 068 private final Map<String, RegionInfo> regionNameToRegionInfoMap; 069 070 /** the regionServer to region map */ 071 private final Map<ServerName, List<RegionInfo>> currentRSToRegionMap; 072 private final Map<ServerName, List<RegionInfo>> secondaryRSToRegionMap; 073 private final Map<ServerName, List<RegionInfo>> teritiaryRSToRegionMap; 074 private final Map<ServerName, List<RegionInfo>> primaryRSToRegionMap; 075 /** the existing assignment plan in the hbase:meta region */ 076 private final FavoredNodesPlan existingAssignmentPlan; 077 private final Set<TableName> disabledTables; 078 private final boolean excludeOfflinedSplitParents; 079 080 public SnapshotOfRegionAssignmentFromMeta(Connection connection) { 081 this(connection, new HashSet<>(), false); 082 } 083 084 public SnapshotOfRegionAssignmentFromMeta(Connection connection, Set<TableName> disabledTables, 085 boolean excludeOfflinedSplitParents) { 086 this.connection = connection; 087 tableToRegionMap = new HashMap<>(); 088 regionToRegionServerMap = new HashMap<>(); 089 currentRSToRegionMap = new HashMap<>(); 090 primaryRSToRegionMap = new HashMap<>(); 091 secondaryRSToRegionMap = new HashMap<>(); 092 teritiaryRSToRegionMap = new HashMap<>(); 093 regionNameToRegionInfoMap = new TreeMap<>(); 094 existingAssignmentPlan = new FavoredNodesPlan(); 095 this.disabledTables = disabledTables; 096 this.excludeOfflinedSplitParents = excludeOfflinedSplitParents; 097 } 098 099 private void processMetaRecord(Result result) throws IOException { 100 if (result == null || result.isEmpty()) { 101 return; 102 } 103 RegionLocations rl = MetaTableAccessor.getRegionLocations(result); 104 if (rl == null) { 105 return; 106 } 107 RegionInfo hri = rl.getRegionLocation(0).getRegion(); 108 if (hri == null) { 109 return; 110 } 111 if (hri.getTable() == null) { 112 return; 113 } 114 if (disabledTables.contains(hri.getTable())) { 115 return; 116 } 117 // Are we to include split parents in the list? 118 if (excludeOfflinedSplitParents && hri.isSplit()) { 119 return; 120 } 121 HRegionLocation[] hrls = rl.getRegionLocations(); 122 123 // Add the current assignment to the snapshot for all replicas 124 for (int i = 0; i < hrls.length; i++) { 125 if (hrls[i] == null) { 126 continue; 127 } 128 hri = hrls[i].getRegion(); 129 if (hri == null) { 130 continue; 131 } 132 addAssignment(hri, hrls[i].getServerName()); 133 addRegion(hri); 134 } 135 136 hri = rl.getRegionLocation(0).getRegion(); 137 // the code below is to handle favored nodes 138 byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY, 139 FavoredNodeAssignmentHelper.FAVOREDNODES_QUALIFIER); 140 if (favoredNodes == null) { 141 return; 142 } 143 // Add the favored nodes into assignment plan 144 ServerName[] favoredServerList = FavoredNodeAssignmentHelper.getFavoredNodesList(favoredNodes); 145 // Add the favored nodes into assignment plan 146 existingAssignmentPlan.updateFavoredNodesMap(hri, Arrays.asList(favoredServerList)); 147 148 /* 149 * Typically there should be FAVORED_NODES_NUM favored nodes for a region in meta. If there is 150 * less than FAVORED_NODES_NUM, lets use as much as we can but log a warning. 151 */ 152 if (favoredServerList.length != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) { 153 LOG.warn("Insufficient favored nodes for region " + hri + " fn: " 154 + Arrays.toString(favoredServerList)); 155 } 156 for (int i = 0; i < favoredServerList.length; i++) { 157 if (i == PRIMARY.ordinal()) { 158 addPrimaryAssignment(hri, favoredServerList[i]); 159 } 160 if (i == SECONDARY.ordinal()) { 161 addSecondaryAssignment(hri, favoredServerList[i]); 162 } 163 if (i == TERTIARY.ordinal()) { 164 addTeritiaryAssignment(hri, favoredServerList[i]); 165 } 166 } 167 } 168 169 /** 170 * Initialize the region assignment snapshot by scanning the hbase:meta table 171 */ 172 public void initialize() throws IOException { 173 LOG.info("Start to scan the hbase:meta for the current region assignment " + "snappshot"); 174 // Scan hbase:meta to pick up user regions 175 try (Table metaTable = connection.getTable(TableName.META_TABLE_NAME); 176 ResultScanner scanner = metaTable.getScanner(HConstants.CATALOG_FAMILY)) { 177 for (;;) { 178 Result result = scanner.next(); 179 if (result == null) { 180 break; 181 } 182 try { 183 processMetaRecord(result); 184 } catch (RuntimeException e) { 185 LOG.error("Catch remote exception " + e.getMessage() + " when processing" + result); 186 throw e; 187 } 188 } 189 } 190 LOG.info("Finished to scan the hbase:meta for the current region assignment" + "snapshot"); 191 } 192 193 private void addRegion(RegionInfo regionInfo) { 194 // Process the region name to region info map 195 regionNameToRegionInfoMap.put(regionInfo.getRegionNameAsString(), regionInfo); 196 197 // Process the table to region map 198 TableName tableName = regionInfo.getTable(); 199 List<RegionInfo> regionList = tableToRegionMap.get(tableName); 200 if (regionList == null) { 201 regionList = new ArrayList<>(); 202 } 203 // Add the current region info into the tableToRegionMap 204 regionList.add(regionInfo); 205 tableToRegionMap.put(tableName, regionList); 206 } 207 208 private void addAssignment(RegionInfo regionInfo, ServerName server) { 209 // Process the region to region server map 210 regionToRegionServerMap.put(regionInfo, server); 211 212 if (server == null) return; 213 214 // Process the region server to region map 215 List<RegionInfo> regionList = currentRSToRegionMap.get(server); 216 if (regionList == null) { 217 regionList = new ArrayList<>(); 218 } 219 regionList.add(regionInfo); 220 currentRSToRegionMap.put(server, regionList); 221 } 222 223 private void addPrimaryAssignment(RegionInfo regionInfo, ServerName server) { 224 // Process the region server to region map 225 List<RegionInfo> regionList = primaryRSToRegionMap.get(server); 226 if (regionList == null) { 227 regionList = new ArrayList<>(); 228 } 229 regionList.add(regionInfo); 230 primaryRSToRegionMap.put(server, regionList); 231 } 232 233 private void addSecondaryAssignment(RegionInfo regionInfo, ServerName server) { 234 // Process the region server to region map 235 List<RegionInfo> regionList = secondaryRSToRegionMap.get(server); 236 if (regionList == null) { 237 regionList = new ArrayList<>(); 238 } 239 regionList.add(regionInfo); 240 secondaryRSToRegionMap.put(server, regionList); 241 } 242 243 private void addTeritiaryAssignment(RegionInfo regionInfo, ServerName server) { 244 // Process the region server to region map 245 List<RegionInfo> regionList = teritiaryRSToRegionMap.get(server); 246 if (regionList == null) { 247 regionList = new ArrayList<>(); 248 } 249 regionList.add(regionInfo); 250 teritiaryRSToRegionMap.put(server, regionList); 251 } 252 253 /** 254 * Get the regioninfo for a region 255 * @return the regioninfo 256 */ 257 public Map<String, RegionInfo> getRegionNameToRegionInfoMap() { 258 return this.regionNameToRegionInfoMap; 259 } 260 261 /** 262 * Get regions for tables 263 * @return a mapping from table to regions 264 */ 265 public Map<TableName, List<RegionInfo>> getTableToRegionMap() { 266 return tableToRegionMap; 267 } 268 269 /** 270 * Get region to region server map 271 * @return region to region server map 272 */ 273 public Map<RegionInfo, ServerName> getRegionToRegionServerMap() { 274 return regionToRegionServerMap; 275 } 276 277 /** 278 * Get regionserver to region map 279 * @return regionserver to region map 280 */ 281 public Map<ServerName, List<RegionInfo>> getRegionServerToRegionMap() { 282 return currentRSToRegionMap; 283 } 284 285 /** 286 * Get the favored nodes plan 287 * @return the existing favored nodes plan 288 */ 289 public FavoredNodesPlan getExistingAssignmentPlan() { 290 return this.existingAssignmentPlan; 291 } 292 293 /** 294 * Get the table set 295 * @return the table set 296 */ 297 public Set<TableName> getTableSet() { 298 return this.tableToRegionMap.keySet(); 299 } 300 301 public Map<ServerName, List<RegionInfo>> getSecondaryToRegionInfoMap() { 302 return this.secondaryRSToRegionMap; 303 } 304 305 public Map<ServerName, List<RegionInfo>> getTertiaryToRegionInfoMap() { 306 return this.teritiaryRSToRegionMap; 307 } 308 309 public Map<ServerName, List<RegionInfo>> getPrimaryToRegionInfoMap() { 310 return this.primaryRSToRegionMap; 311 } 312}