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 snappshot"); 107 // TODO: at some point this code could live in the MetaTableAccessor 108 Visitor v = new Visitor() { 109 @Override 110 public boolean visit(Result result) throws IOException { 111 try { 112 if (result == null || result.isEmpty()) return true; 113 RegionLocations rl = MetaTableAccessor.getRegionLocations(result); 114 if (rl == null) return true; 115 RegionInfo hri = rl.getRegionLocation(0).getRegionInfo(); 116 if (hri == null) return true; 117 if (hri.getTable() == null) return true; 118 if (disabledTables.contains(hri.getTable())) { 119 return true; 120 } 121 // Are we to include split parents in the list? 122 if (excludeOfflinedSplitParents && hri.isSplit()) return true; 123 HRegionLocation[] hrls = rl.getRegionLocations(); 124 125 // Add the current assignment to the snapshot for all replicas 126 for (int i = 0; i < hrls.length; i++) { 127 if (hrls[i] == null) continue; 128 hri = hrls[i].getRegionInfo(); 129 if (hri == null) continue; 130 addAssignment(hri, hrls[i].getServerName()); 131 addRegion(hri); 132 } 133 134 hri = rl.getRegionLocation(0).getRegionInfo(); 135 // the code below is to handle favored nodes 136 byte[] favoredNodes = result.getValue(HConstants.CATALOG_FAMILY, 137 FavoredNodeAssignmentHelper.FAVOREDNODES_QUALIFIER); 138 if (favoredNodes == null) return true; 139 // Add the favored nodes into assignment plan 140 ServerName[] favoredServerList = 141 FavoredNodeAssignmentHelper.getFavoredNodesList(favoredNodes); 142 // Add the favored nodes into assignment plan 143 existingAssignmentPlan.updateFavoredNodesMap(hri, 144 Arrays.asList(favoredServerList)); 145 146 /* 147 * Typically there should be FAVORED_NODES_NUM favored nodes for a region in meta. If 148 * there is less than FAVORED_NODES_NUM, lets use as much as we can but log a warning. 149 */ 150 if (favoredServerList.length != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) { 151 LOG.warn("Insufficient favored nodes for region " + hri + " fn: " + Arrays 152 .toString(favoredServerList)); 153 } 154 for (int i = 0; i < favoredServerList.length; i++) { 155 if (i == PRIMARY.ordinal()) addPrimaryAssignment(hri, favoredServerList[i]); 156 if (i == SECONDARY.ordinal()) addSecondaryAssignment(hri, favoredServerList[i]); 157 if (i == TERTIARY.ordinal()) addTeritiaryAssignment(hri, favoredServerList[i]); 158 } 159 return true; 160 } catch (RuntimeException e) { 161 LOG.error("Catche remote exception " + e.getMessage() + 162 " when processing" + result); 163 throw e; 164 } 165 } 166 }; 167 // Scan hbase:meta to pick up user regions 168 MetaTableAccessor.fullScanRegions(connection, v); 169 //regionToRegionServerMap = regions; 170 LOG.info("Finished to scan the hbase:meta for the current region assignment snapshot"); 171 } 172 173 private void addRegion(RegionInfo regionInfo) { 174 // Process the region name to region info map 175 regionNameToRegionInfoMap.put(regionInfo.getRegionNameAsString(), regionInfo); 176 177 // Process the table to region map 178 TableName tableName = regionInfo.getTable(); 179 List<RegionInfo> regionList = tableToRegionMap.get(tableName); 180 if (regionList == null) { 181 regionList = new ArrayList<>(); 182 } 183 // Add the current region info into the tableToRegionMap 184 regionList.add(regionInfo); 185 tableToRegionMap.put(tableName, regionList); 186 } 187 188 private void addAssignment(RegionInfo regionInfo, ServerName server) { 189 // Process the region to region server map 190 regionToRegionServerMap.put(regionInfo, server); 191 192 if (server == null) return; 193 194 // Process the region server to region map 195 List<RegionInfo> regionList = currentRSToRegionMap.get(server); 196 if (regionList == null) { 197 regionList = new ArrayList<>(); 198 } 199 regionList.add(regionInfo); 200 currentRSToRegionMap.put(server, regionList); 201 } 202 203 private void addPrimaryAssignment(RegionInfo regionInfo, ServerName server) { 204 // Process the region server to region map 205 List<RegionInfo> regionList = primaryRSToRegionMap.get(server); 206 if (regionList == null) { 207 regionList = new ArrayList<>(); 208 } 209 regionList.add(regionInfo); 210 primaryRSToRegionMap.put(server, regionList); 211 } 212 213 private void addSecondaryAssignment(RegionInfo regionInfo, ServerName server) { 214 // Process the region server to region map 215 List<RegionInfo> regionList = secondaryRSToRegionMap.get(server); 216 if (regionList == null) { 217 regionList = new ArrayList<>(); 218 } 219 regionList.add(regionInfo); 220 secondaryRSToRegionMap.put(server, regionList); 221 } 222 223 private void addTeritiaryAssignment(RegionInfo regionInfo, ServerName server) { 224 // Process the region server to region map 225 List<RegionInfo> regionList = teritiaryRSToRegionMap.get(server); 226 if (regionList == null) { 227 regionList = new ArrayList<>(); 228 } 229 regionList.add(regionInfo); 230 teritiaryRSToRegionMap.put(server, regionList); 231 } 232 233 /** 234 * Get the regioninfo for a region 235 * @return the regioninfo 236 */ 237 public Map<String, RegionInfo> getRegionNameToRegionInfoMap() { 238 return this.regionNameToRegionInfoMap; 239 } 240 241 /** 242 * Get regions for tables 243 * @return a mapping from table to regions 244 */ 245 public Map<TableName, List<RegionInfo>> getTableToRegionMap() { 246 return tableToRegionMap; 247 } 248 249 /** 250 * Get region to region server map 251 * @return region to region server map 252 */ 253 public Map<RegionInfo, ServerName> getRegionToRegionServerMap() { 254 return regionToRegionServerMap; 255 } 256 257 /** 258 * Get regionserver to region map 259 * @return regionserver to region map 260 */ 261 public Map<ServerName, List<RegionInfo>> getRegionServerToRegionMap() { 262 return currentRSToRegionMap; 263 } 264 265 /** 266 * Get the favored nodes plan 267 * @return the existing favored nodes plan 268 */ 269 public FavoredNodesPlan getExistingAssignmentPlan() { 270 return this.existingAssignmentPlan; 271 } 272 273 /** 274 * Get the table set 275 * @return the table set 276 */ 277 public Set<TableName> getTableSet() { 278 return this.tableToRegionMap.keySet(); 279 } 280 281 public Map<ServerName, List<RegionInfo>> getSecondaryToRegionInfoMap() { 282 return this.secondaryRSToRegionMap; 283 } 284 285 public Map<ServerName, List<RegionInfo>> getTertiaryToRegionInfoMap() { 286 return this.teritiaryRSToRegionMap; 287 } 288 289 public Map<ServerName, List<RegionInfo>> getPrimaryToRegionInfoMap() { 290 return this.primaryRSToRegionMap; 291 } 292}