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    
019    package org.apache.hadoop.net;
020    
021    import org.apache.hadoop.classification.InterfaceAudience;
022    import org.apache.hadoop.classification.InterfaceStability;
023    import org.apache.hadoop.conf.Configurable;
024    import org.apache.hadoop.conf.Configuration;
025    import org.apache.hadoop.fs.CommonConfigurationKeys;
026    
027    import java.util.HashMap;
028    import java.util.HashSet;
029    import java.util.Map;
030    import 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
048    public 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    }