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.CatalogFamilyFormat; 034import org.apache.hadoop.hbase.HConstants; 035import org.apache.hadoop.hbase.HRegionLocation; 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 = CatalogFamilyFormat.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 {} for the current region assignment snapshot", 174 TableName.META_TABLE_NAME); 175 // Scan hbase:meta to pick up user regions 176 try (Table metaTable = connection.getTable(TableName.META_TABLE_NAME); 177 ResultScanner scanner = metaTable.getScanner(HConstants.CATALOG_FAMILY)) { 178 for (;;) { 179 Result result = scanner.next(); 180 if (result == null) { 181 break; 182 } 183 try { 184 processMetaRecord(result); 185 } catch (RuntimeException e) { 186 LOG.error("Catch remote exception " + e.getMessage() + " when processing" + result); 187 throw e; 188 } 189 } 190 } 191 LOG.info("Finished scanning {} for the current region assignment snapshot", 192 TableName.META_TABLE_NAME); 193 } 194 195 private void addRegion(RegionInfo regionInfo) { 196 // Process the region name to region info map 197 regionNameToRegionInfoMap.put(regionInfo.getRegionNameAsString(), regionInfo); 198 199 // Process the table to region map 200 TableName tableName = regionInfo.getTable(); 201 List<RegionInfo> regionList = tableToRegionMap.get(tableName); 202 if (regionList == null) { 203 regionList = new ArrayList<>(); 204 } 205 // Add the current region info into the tableToRegionMap 206 regionList.add(regionInfo); 207 tableToRegionMap.put(tableName, regionList); 208 } 209 210 private void addAssignment(RegionInfo regionInfo, ServerName server) { 211 // Process the region to region server map 212 regionToRegionServerMap.put(regionInfo, server); 213 214 if (server == null) return; 215 216 // Process the region server to region map 217 List<RegionInfo> regionList = currentRSToRegionMap.get(server); 218 if (regionList == null) { 219 regionList = new ArrayList<>(); 220 } 221 regionList.add(regionInfo); 222 currentRSToRegionMap.put(server, regionList); 223 } 224 225 private void addPrimaryAssignment(RegionInfo regionInfo, ServerName server) { 226 // Process the region server to region map 227 List<RegionInfo> regionList = primaryRSToRegionMap.get(server); 228 if (regionList == null) { 229 regionList = new ArrayList<>(); 230 } 231 regionList.add(regionInfo); 232 primaryRSToRegionMap.put(server, regionList); 233 } 234 235 private void addSecondaryAssignment(RegionInfo regionInfo, ServerName server) { 236 // Process the region server to region map 237 List<RegionInfo> regionList = secondaryRSToRegionMap.get(server); 238 if (regionList == null) { 239 regionList = new ArrayList<>(); 240 } 241 regionList.add(regionInfo); 242 secondaryRSToRegionMap.put(server, regionList); 243 } 244 245 private void addTeritiaryAssignment(RegionInfo regionInfo, ServerName server) { 246 // Process the region server to region map 247 List<RegionInfo> regionList = teritiaryRSToRegionMap.get(server); 248 if (regionList == null) { 249 regionList = new ArrayList<>(); 250 } 251 regionList.add(regionInfo); 252 teritiaryRSToRegionMap.put(server, regionList); 253 } 254 255 /** 256 * Get the regioninfo for a region 257 * @return the regioninfo 258 */ 259 public Map<String, RegionInfo> getRegionNameToRegionInfoMap() { 260 return this.regionNameToRegionInfoMap; 261 } 262 263 /** 264 * Get regions for tables 265 * @return a mapping from table to regions 266 */ 267 public Map<TableName, List<RegionInfo>> getTableToRegionMap() { 268 return tableToRegionMap; 269 } 270 271 /** 272 * Get region to region server map 273 * @return region to region server map 274 */ 275 public Map<RegionInfo, ServerName> getRegionToRegionServerMap() { 276 return regionToRegionServerMap; 277 } 278 279 /** 280 * Get regionserver to region map 281 * @return regionserver to region map 282 */ 283 public Map<ServerName, List<RegionInfo>> getRegionServerToRegionMap() { 284 return currentRSToRegionMap; 285 } 286 287 /** 288 * Get the favored nodes plan 289 * @return the existing favored nodes plan 290 */ 291 public FavoredNodesPlan getExistingAssignmentPlan() { 292 return this.existingAssignmentPlan; 293 } 294 295 /** 296 * Get the table set 297 * @return the table set 298 */ 299 public Set<TableName> getTableSet() { 300 return this.tableToRegionMap.keySet(); 301 } 302 303 public Map<ServerName, List<RegionInfo>> getSecondaryToRegionInfoMap() { 304 return this.secondaryRSToRegionMap; 305 } 306 307 public Map<ServerName, List<RegionInfo>> getTertiaryToRegionInfoMap() { 308 return this.teritiaryRSToRegionMap; 309 } 310 311 public Map<ServerName, List<RegionInfo>> getPrimaryToRegionInfoMap() { 312 return this.primaryRSToRegionMap; 313 } 314}