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.favored; 019 020import java.util.ArrayList; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.ConcurrentHashMap; 024import java.util.stream.Collectors; 025import org.apache.hadoop.hbase.ServerName; 026import org.apache.hadoop.hbase.client.RegionInfo; 027import org.apache.yetus.audience.InterfaceAudience; 028 029/** 030 * This class contains the mapping information between each region name and its favored region 031 * server list. Used by FavoredNodeLoadBalancer set of classes and from unit tests (hence the class 032 * is public) All the access to this class is thread-safe. 033 */ 034@InterfaceAudience.Private 035public class FavoredNodesPlan { 036 /** The map between each region name and its favored region server list */ 037 private final Map<String, List<ServerName>> favoredNodesMap; 038 039 public static enum Position { 040 PRIMARY, 041 SECONDARY, 042 TERTIARY 043 } 044 045 public FavoredNodesPlan() { 046 this.favoredNodesMap = new ConcurrentHashMap<>(); 047 } 048 049 /** 050 * Add to existing Map of FavoredNodes. 051 */ 052 void updateFavoredNodesMap(FavoredNodesPlan fnp) { 053 this.favoredNodesMap.putAll(fnp.favoredNodesMap); 054 } 055 056 /** 057 * Update an assignment to the plan 058 */ 059 public void updateFavoredNodesMap(RegionInfo region, List<ServerName> servers) { 060 if (region == null || servers == null || servers.isEmpty()) { 061 return; 062 } 063 this.favoredNodesMap.put(region.getRegionNameAsString(), servers); 064 } 065 066 /** 067 * Remove a favored node assignment 068 * @return the list of favored region server for this region based on the plan 069 */ 070 List<ServerName> removeFavoredNodes(RegionInfo region) { 071 return favoredNodesMap.remove(region.getRegionNameAsString()); 072 } 073 074 /** 075 * Returns the list of favored region server for this region based on the plan 076 */ 077 public List<ServerName> getFavoredNodes(RegionInfo region) { 078 return favoredNodesMap.get(region.getRegionNameAsString()); 079 } 080 081 /** 082 * Return the position of the server in the favoredNodes list. Assumes the favoredNodes list is of 083 * size 3. 084 */ 085 public static Position getFavoredServerPosition(List<ServerName> favoredNodes, 086 ServerName server) { 087 if ( 088 favoredNodes == null || server == null 089 || favoredNodes.size() != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM 090 ) { 091 return null; 092 } 093 for (Position p : Position.values()) { 094 if (ServerName.isSameAddress(favoredNodes.get(p.ordinal()), server)) { 095 return p; 096 } 097 } 098 return null; 099 } 100 101 /** 102 * Return the mapping between each region to its favored region server list. 103 */ 104 public Map<String, List<ServerName>> getAssignmentMap() { 105 // Make a deep copy so changes don't harm our copy of favoredNodesMap. 106 return this.favoredNodesMap.entrySet().stream() 107 .collect(Collectors.toMap(k -> k.getKey(), v -> new ArrayList<ServerName>(v.getValue()))); 108 } 109 110 public int size() { 111 return this.favoredNodesMap.size(); 112 } 113 114 @Override 115 public boolean equals(Object o) { 116 if (this == o) { 117 return true; 118 } 119 if (o == null) { 120 return false; 121 } 122 if (!(o instanceof FavoredNodesPlan)) { 123 return false; 124 } 125 // To compare the map from object o is identical to current assignment map. 126 Map<String, List<ServerName>> comparedMap = ((FavoredNodesPlan) o).favoredNodesMap; 127 128 // compare the size 129 if (comparedMap.size() != this.favoredNodesMap.size()) { 130 return false; 131 } 132 133 // compare each element in the assignment map 134 for (Map.Entry<String, List<ServerName>> entry : comparedMap.entrySet()) { 135 List<ServerName> serverList = this.favoredNodesMap.get(entry.getKey()); 136 if (serverList == null && entry.getValue() != null) { 137 return false; 138 } else if (serverList != null && !serverList.equals(entry.getValue())) { 139 return false; 140 } 141 } 142 return true; 143 } 144 145 @Override 146 public int hashCode() { 147 return favoredNodesMap.hashCode(); 148 } 149}