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 {@link FavoredNodeLoadBalancer} set of classes and from unit tests (hence 032 * the class 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 /** Returns the list of favored region server for this region based on the plan */ 075 public List<ServerName> getFavoredNodes(RegionInfo region) { 076 return favoredNodesMap.get(region.getRegionNameAsString()); 077 } 078 079 /** 080 * Return the position of the server in the favoredNodes list. Assumes the favoredNodes list is of 081 * size 3. 082 */ 083 public static Position getFavoredServerPosition(List<ServerName> favoredNodes, 084 ServerName server) { 085 if ( 086 favoredNodes == null || server == null 087 || favoredNodes.size() != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM 088 ) { 089 return null; 090 } 091 for (Position p : Position.values()) { 092 if (ServerName.isSameAddress(favoredNodes.get(p.ordinal()), server)) { 093 return p; 094 } 095 } 096 return null; 097 } 098 099 /** 100 * Return the mapping between each region to its favored region server list. 101 */ 102 public Map<String, List<ServerName>> getAssignmentMap() { 103 // Make a deep copy so changes don't harm our copy of favoredNodesMap. 104 return this.favoredNodesMap.entrySet().stream() 105 .collect(Collectors.toMap(k -> k.getKey(), v -> new ArrayList<ServerName>(v.getValue()))); 106 } 107 108 public int size() { 109 return this.favoredNodesMap.size(); 110 } 111 112 @Override 113 public boolean equals(Object o) { 114 if (this == o) { 115 return true; 116 } 117 if (o == null) { 118 return false; 119 } 120 if (!(o instanceof FavoredNodesPlan)) { 121 return false; 122 } 123 // To compare the map from object o is identical to current assignment map. 124 Map<String, List<ServerName>> comparedMap = ((FavoredNodesPlan) o).favoredNodesMap; 125 126 // compare the size 127 if (comparedMap.size() != this.favoredNodesMap.size()) { 128 return false; 129 } 130 131 // compare each element in the assignment map 132 for (Map.Entry<String, List<ServerName>> entry : comparedMap.entrySet()) { 133 List<ServerName> serverList = this.favoredNodesMap.get(entry.getKey()); 134 if (serverList == null && entry.getValue() != null) { 135 return false; 136 } else if (serverList != null && !serverList.equals(entry.getValue())) { 137 return false; 138 } 139 } 140 return true; 141 } 142 143 @Override 144 public int hashCode() { 145 return favoredNodesMap.hashCode(); 146 } 147}