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.List;
022import java.util.Map;
023import java.util.concurrent.ConcurrentHashMap;
024
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
031 * its favored region server list. Used by {@link FavoredNodeLoadBalancer} set
032 * of classes and from unit tests (hence the class is public)
033 *
034 * All the access to this class is thread-safe.
035 */
036@InterfaceAudience.Private
037public class FavoredNodesPlan {
038
039  /** the map between each region name and its favored region server list */
040  private Map<String, List<ServerName>> favoredNodesMap;
041
042  public static enum Position {
043    PRIMARY,
044    SECONDARY,
045    TERTIARY
046  }
047
048  public FavoredNodesPlan() {
049    favoredNodesMap = new ConcurrentHashMap<>();
050  }
051
052  /**
053   * Update an assignment to the plan
054   * @param region
055   * @param servers
056   */
057  public void updateFavoredNodesMap(RegionInfo region, List<ServerName> servers) {
058    if (region == null || servers == null || servers.isEmpty()) {
059      return;
060    }
061    this.favoredNodesMap.put(region.getRegionNameAsString(), servers);
062  }
063
064  /**
065   * Remove a favored node assignment
066   * @param region region
067   * @return the list of favored region server for this region based on the plan
068   */
069  public List<ServerName> removeFavoredNodes(RegionInfo region) {
070    return favoredNodesMap.remove(region.getRegionNameAsString());
071  }
072
073  /**
074   * @param region
075   * @return 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
083   * favoredNodes list is of size 3.
084   * @param favoredNodes
085   * @param server
086   * @return position
087   */
088  public static Position getFavoredServerPosition(
089      List<ServerName> favoredNodes, ServerName server) {
090    if (favoredNodes == null || server == null ||
091        favoredNodes.size() != FavoredNodeAssignmentHelper.FAVORED_NODES_NUM) {
092      return null;
093    }
094    for (Position p : Position.values()) {
095      if (ServerName.isSameAddress(favoredNodes.get(p.ordinal()),server)) {
096        return p;
097      }
098    }
099    return null;
100  }
101
102  /**
103   * @return the mapping between each region to its favored region server list
104   */
105  public Map<String, List<ServerName>> getAssignmentMap() {
106    return favoredNodesMap;
107  }
108
109  @Override
110  public boolean equals(Object o) {
111    if (this == o) {
112      return true;
113    }
114    if (o == null) {
115      return false;
116    }
117    if (getClass() != o.getClass()) {
118      return false;
119    }
120    // To compare the map from objec o is identical to current assignment map.
121    Map<String, List<ServerName>> comparedMap = ((FavoredNodesPlan)o).getAssignmentMap();
122
123    // compare the size
124    if (comparedMap.size() != this.favoredNodesMap.size())
125      return false;
126
127    // compare each element in the assignment map
128    for (Map.Entry<String, List<ServerName>> entry :
129      comparedMap.entrySet()) {
130      List<ServerName> serverList = this.favoredNodesMap.get(entry.getKey());
131      if (serverList == null && entry.getValue() != null) {
132        return false;
133      } else if (serverList != null && !serverList.equals(entry.getValue())) {
134        return false;
135      }
136    }
137    return true;
138  }
139
140  @Override
141  public int hashCode() {
142    return favoredNodesMap.hashCode();
143  }
144}