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