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 */
018
019package org.apache.hadoop.net;
020
021import org.apache.hadoop.classification.InterfaceAudience;
022import org.apache.hadoop.classification.InterfaceStability;
023import org.apache.hadoop.conf.Configurable;
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.fs.CommonConfigurationKeys;
026
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.Map;
030import java.util.Set;
031
032/**
033 * This is a base class for DNS to Switch mappings. <p/> It is not mandatory to
034 * derive {@link DNSToSwitchMapping} implementations from it, but it is strongly
035 * recommended, as it makes it easy for the Hadoop developers to add new methods
036 * to this base class that are automatically picked up by all implementations.
037 * <p/>
038 *
039 * This class does not extend the <code>Configured</code>
040 * base class, and should not be changed to do so, as it causes problems
041 * for subclasses. The constructor of the <code>Configured</code> calls
042 * the  {@link #setConf(Configuration)} method, which will call into the
043 * subclasses before they have been fully constructed.
044 *
045 */
046@InterfaceAudience.Public
047@InterfaceStability.Evolving
048public abstract class AbstractDNSToSwitchMapping
049    implements DNSToSwitchMapping, Configurable {
050
051  private Configuration conf;
052
053  /**
054   * Create an unconfigured instance
055   */
056  protected AbstractDNSToSwitchMapping() {
057  }
058
059  /**
060   * Create an instance, caching the configuration file.
061   * This constructor does not call {@link #setConf(Configuration)}; if
062   * a subclass extracts information in that method, it must call it explicitly.
063   * @param conf the configuration
064   */
065  protected AbstractDNSToSwitchMapping(Configuration conf) {
066    this.conf = conf;
067  }
068
069  @Override
070  public Configuration getConf() {
071    return conf;
072  }
073
074  @Override
075  public void setConf(Configuration conf) {
076    this.conf = conf;
077  }
078
079  /**
080   * Predicate that indicates that the switch mapping is known to be
081   * single-switch. The base class returns false: it assumes all mappings are
082   * multi-rack. Subclasses may override this with methods that are more aware
083   * of their topologies.
084   *
085   * <p/>
086   *
087   * This method is used when parts of Hadoop need know whether to apply
088   * single rack vs multi-rack policies, such as during block placement.
089   * Such algorithms behave differently if they are on multi-switch systems.
090   * </p>
091   *
092   * @return true if the mapping thinks that it is on a single switch
093   */
094  public boolean isSingleSwitch() {
095    return false;
096  }
097
098  /**
099   * Get a copy of the map (for diagnostics)
100   * @return a clone of the map or null for none known
101   */
102  public Map<String, String> getSwitchMap() {
103    return null;
104  }
105
106  /**
107   * Generate a string listing the switch mapping implementation,
108   * the mapping for every known node and the number of nodes and
109   * unique switches known about -each entry to a separate line.
110   * @return a string that can be presented to the ops team or used in
111   * debug messages.
112   */
113  public String dumpTopology() {
114    Map<String, String> rack = getSwitchMap();
115    StringBuilder builder = new StringBuilder();
116    builder.append("Mapping: ").append(toString()).append("\n");
117    if (rack != null) {
118      builder.append("Map:\n");
119      Set<String> switches = new HashSet<String>();
120      for (Map.Entry<String, String> entry : rack.entrySet()) {
121        builder.append("  ")
122            .append(entry.getKey())
123            .append(" -> ")
124            .append(entry.getValue())
125            .append("\n");
126        switches.add(entry.getValue());
127      }
128      builder.append("Nodes: ").append(rack.size()).append("\n");
129      builder.append("Switches: ").append(switches.size()).append("\n");
130    } else {
131      builder.append("No topology information");
132    }
133    return builder.toString();
134  }
135
136  protected boolean isSingleSwitchByScriptPolicy() {
137    return conf != null
138        && conf.get(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY) == null;
139  }
140
141  /**
142   * Query for a {@link DNSToSwitchMapping} instance being on a single
143   * switch.
144   * <p/>
145   * This predicate simply assumes that all mappings not derived from
146   * this class are multi-switch.
147   * @param mapping the mapping to query
148   * @return true if the base class says it is single switch, or the mapping
149   * is not derived from this class.
150   */
151  public static boolean isMappingSingleSwitch(DNSToSwitchMapping mapping) {
152    return mapping != null && mapping instanceof AbstractDNSToSwitchMapping
153        && ((AbstractDNSToSwitchMapping) mapping).isSingleSwitch();
154  }
155
156}