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 }