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.HashSet;
028    import java.util.Map;
029    import 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
047    public 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    }