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