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 }