001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.master; 020 021import static org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position.PRIMARY; 022import static org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position.SECONDARY; 023import static org.apache.hadoop.hbase.favored.FavoredNodesPlan.Position.TERTIARY; 024 025import java.io.IOException; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.HashMap; 029import java.util.HashSet; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033import java.util.TreeMap; 034 035import org.apache.hadoop.hbase.HConstants; 036import org.apache.hadoop.hbase.HRegionLocation; 037import org.apache.hadoop.hbase.MetaTableAccessor; 038import org.apache.hadoop.hbase.MetaTableAccessor.Visitor; 039import org.apache.hadoop.hbase.RegionLocations; 040import org.apache.hadoop.hbase.ServerName; 041import org.apache.hadoop.hbase.TableName; 042import org.apache.hadoop.hbase.client.Connection; 043import org.apache.hadoop.hbase.client.RegionInfo; 044import org.apache.hadoop.hbase.client.Result; 045import org.apache.hadoop.hbase.favored.FavoredNodeAssignmentHelper; 046import org.apache.hadoop.hbase.favored.FavoredNodesPlan; 047import org.apache.yetus.audience.InterfaceAudience; 048import org.slf4j.Logger; 049import org.slf4j.LoggerFactory; 050 051/** 052 * Used internally for reading meta and constructing datastructures that are 053 * then queried, for things like regions to regionservers, table to regions, etc. 054 * It also records the favored nodes mapping for regions. 055 * 056 */ 057@InterfaceAudience.Private 058public class SnapshotOfRegionAssignmentFromMeta { 059 private static final Logger LOG = LoggerFactory.getLogger(SnapshotOfRegionAssignmentFromMeta.class 060 .getName()); 061 062 private final Connection connection; 063 064 /** the table name to region map */ 065 private final Map<TableName, List<RegionInfo>> tableToRegionMap; 066 /** the region to region server map */ 067 //private final Map<RegionInfo, ServerName> regionToRegionServerMap; 068 private Map<RegionInfo, ServerName> regionToRegionServerMap; 069 /** the region name to region info map */ 070 private final Map<String, RegionInfo> regionNameToRegionInfoMap; 071 072 /** the regionServer to region map */ 073 private final Map<ServerName, List<RegionInfo>> currentRSToRegionMap; 074 private final Map<ServerName, List<RegionInfo>> secondaryRSToRegionMap; 075 private final Map<ServerName, List<RegionInfo>> teritiaryRSToRegionMap; 076 private final Map<ServerName, List<RegionInfo>> primaryRSToRegionMap; 077 /** the existing assignment plan in the hbase:meta region */ 078 private final FavoredNodesPlan existingAssignmentPlan; 079 private final Set<TableName> disabledTables; 080 private final boolean excludeOfflinedSplitParents; 081 082 public SnapshotOfRegionAssignmentFromMeta(Connection connection) { 083 this(connection, new HashSet<>(), false); 084 } 085 086 public SnapshotOfRegionAssignmentFromMeta(Connection connection, Set<TableName> disabledTables, 087 boolean excludeOfflinedSplitParents) { 088 this.connection = connection; 089 tableToRegionMap = new HashMap<>(); 090 regionToRegionServerMap = new HashMap<>(); 091 currentRSToRegionMap = new HashMap<>(); 092 primaryRSToRegionMap = new HashMap<>(); 093 secondaryRSToRegionMap = new HashMap<>(); 094 teritiaryRSToRegionMap = new HashMap<>(); 095 regionNameToRegionInfoMap = new TreeMap<>(); 096 existingAssignmentPlan = new FavoredNodesPlan(); 097 this.disabledTables = disabledTables; 098 this.excludeOfflinedSplitParents = excludeOfflinedSplitParents; 099 } 100 101 /** 102 * Initialize the region assignment snapshot by scanning the hbase:meta table 103 * @throws IOException 104 */ 105 public void initialize() throws IOException { 106 LOG.info("Start to scan the hbase:meta for the current region assignment " + 107 "snappshot"); 108 // TODO: at some point this code could live in the MetaTableAccessor 109 Visitor v = new Visitor() { 110 @Override 111 public boolean visit(Result result) throws IOException { 112 try { 113 if (result == null || result.isEmpty()) return true; 114 RegionLocations rl = MetaTableAccessor.getRegionLocations(result); 115 if (rl == null) return true; 116 RegionInfo hri = rl.getRegionLocation(0).getRegionInfo(); 117 if (hri == null) return true; 118 if (hri.getTable() == null) return true; 119 if (disabledTables.contains(hri.getTable())) { 120 return true; 121 } 122 // Are we to include split parents in the list? 123 if (excludeOfflinedSplitParents && hri.isSplit()) return true; 124 HRegionLocation[] hrls = rl.getRegionLocations(); 125 126 // Add the current assignment to the snapshot for all replicas 127 for (int i = 0; i < hrls.length; i++) { 128 if (hrls[i] == null) continue; 129 hri = hrls[i].getRegionInfo(); 130 if (hri == null) continue; 131 addAssignment(hri, hrls[i].getServerName()); 132 addRegion(hri); 133 } 134 135 hri = rl.getRegionLocation(0).getRegionInfo(); 136 // the code below is to handle favored nodes 137 byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY, 138 FavoredNodeAssignmentHelper.FAVOREDNODES_QUALIFIER); 139 if (favoredNodes == null) return true; 140 // Add the favored nodes into assignment plan 141 ServerName[] favoredServerList = 142 FavoredNodeAssignmentHelper.getFavoredNodesList(favoredNodes); 143 // Add the favored nodes into assignment plan 144 existingAssignmentPlan.updateFavoredNodesMap(hri, 145 Arrays.asList(favoredServerList)); 146 147 /* 148 * Typically there should be FAVORED_NODES_NUM favored nodes for a region in meta. If 149 * there is less than FAVORED_NODES_NUM, lets use as much as we can but log a warning. 150 */ 151 if (favoredServerList.length != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) { 152 LOG.warn("Insufficient favored nodes for region " + hri + " fn: " + Arrays 153 .toString(favoredServerList)); 154 } 155 for (int i = 0; i < favoredServerList.length; i++) { 156 if (i == PRIMARY.ordinal()) addPrimaryAssignment(hri, favoredServerList[i]); 157 if (i == SECONDARY.ordinal()) addSecondaryAssignment(hri, favoredServerList[i]); 158 if (i == TERTIARY.ordinal()) addTeritiaryAssignment(hri, favoredServerList[i]); 159 } 160 return true; 161 } catch (RuntimeException e) { 162 LOG.error("Catche remote exception " + e.getMessage() + 163 " when processing" + result); 164 throw e; 165 } 166 } 167 }; 168 // Scan hbase:meta to pick up user regions 169 MetaTableAccessor.fullScanRegions(connection, v); 170 //regionToRegionServerMap = regions; 171 LOG.info("Finished to scan the hbase:meta for the current region assignment" + 172 "snapshot"); 173 } 174 175 private void addRegion(RegionInfo regionInfo) { 176 // Process the region name to region info map 177 regionNameToRegionInfoMap.put(regionInfo.getRegionNameAsString(), regionInfo); 178 179 // Process the table to region map 180 TableName tableName = regionInfo.getTable(); 181 List<RegionInfo> regionList = tableToRegionMap.get(tableName); 182 if (regionList == null) { 183 regionList = new ArrayList<>(); 184 } 185 // Add the current region info into the tableToRegionMap 186 regionList.add(regionInfo); 187 tableToRegionMap.put(tableName, regionList); 188 } 189 190 private void addAssignment(RegionInfo regionInfo, ServerName server) { 191 // Process the region to region server map 192 regionToRegionServerMap.put(regionInfo, server); 193 194 if (server == null) return; 195 196 // Process the region server to region map 197 List<RegionInfo> regionList = currentRSToRegionMap.get(server); 198 if (regionList == null) { 199 regionList = new ArrayList<>(); 200 } 201 regionList.add(regionInfo); 202 currentRSToRegionMap.put(server, regionList); 203 } 204 205 private void addPrimaryAssignment(RegionInfo regionInfo, ServerName server) { 206 // Process the region server to region map 207 List<RegionInfo> regionList = primaryRSToRegionMap.get(server); 208 if (regionList == null) { 209 regionList = new ArrayList<>(); 210 } 211 regionList.add(regionInfo); 212 primaryRSToRegionMap.put(server, regionList); 213 } 214 215 private void addSecondaryAssignment(RegionInfo regionInfo, ServerName server) { 216 // Process the region server to region map 217 List<RegionInfo> regionList = secondaryRSToRegionMap.get(server); 218 if (regionList == null) { 219 regionList = new ArrayList<>(); 220 } 221 regionList.add(regionInfo); 222 secondaryRSToRegionMap.put(server, regionList); 223 } 224 225 private void addTeritiaryAssignment(RegionInfo regionInfo, ServerName server) { 226 // Process the region server to region map 227 List<RegionInfo> regionList = teritiaryRSToRegionMap.get(server); 228 if (regionList == null) { 229 regionList = new ArrayList<>(); 230 } 231 regionList.add(regionInfo); 232 teritiaryRSToRegionMap.put(server, regionList); 233 } 234 235 /** 236 * Get the regioninfo for a region 237 * @return the regioninfo 238 */ 239 public Map<String, RegionInfo> getRegionNameToRegionInfoMap() { 240 return this.regionNameToRegionInfoMap; 241 } 242 243 /** 244 * Get regions for tables 245 * @return a mapping from table to regions 246 */ 247 public Map<TableName, List<RegionInfo>> getTableToRegionMap() { 248 return tableToRegionMap; 249 } 250 251 /** 252 * Get region to region server map 253 * @return region to region server map 254 */ 255 public Map<RegionInfo, ServerName> getRegionToRegionServerMap() { 256 return regionToRegionServerMap; 257 } 258 259 /** 260 * Get regionserver to region map 261 * @return regionserver to region map 262 */ 263 public Map<ServerName, List<RegionInfo>> getRegionServerToRegionMap() { 264 return currentRSToRegionMap; 265 } 266 267 /** 268 * Get the favored nodes plan 269 * @return the existing favored nodes plan 270 */ 271 public FavoredNodesPlan getExistingAssignmentPlan() { 272 return this.existingAssignmentPlan; 273 } 274 275 /** 276 * Get the table set 277 * @return the table set 278 */ 279 public Set<TableName> getTableSet() { 280 return this.tableToRegionMap.keySet(); 281 } 282 283 public Map<ServerName, List<RegionInfo>> getSecondaryToRegionInfoMap() { 284 return this.secondaryRSToRegionMap; 285 } 286 287 public Map<ServerName, List<RegionInfo>> getTertiaryToRegionInfoMap() { 288 return this.teritiaryRSToRegionMap; 289 } 290 291 public Map<ServerName, List<RegionInfo>> getPrimaryToRegionInfoMap() { 292 return this.primaryRSToRegionMap; 293 } 294}