Skip to content

Commit fd13a71

Browse files
committed
HADOOP-7777 a base class for DNSToSwitchMapping implementations
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1206515 13f79535-47bb-0310-9956-ffa450edef68
1 parent 150ccf9 commit fd13a71

File tree

8 files changed

+507
-88
lines changed

8 files changed

+507
-88
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.net;
20+
21+
import org.apache.hadoop.classification.InterfaceAudience;
22+
import org.apache.hadoop.classification.InterfaceStability;
23+
import org.apache.hadoop.conf.Configurable;
24+
import org.apache.hadoop.conf.Configuration;
25+
26+
/**
27+
* This is a base class for DNS to Switch mappings. <p/> It is not mandatory to
28+
* derive {@link DNSToSwitchMapping} implementations from it, but it is strongly
29+
* recommended, as it makes it easy for the Hadoop developers to add new methods
30+
* to this base class that are automatically picked up by all implementations.
31+
* <p/>
32+
*
33+
* This class does not extend the <code>Configured</code>
34+
* base class, and should not be changed to do so, as it causes problems
35+
* for subclasses. The constructor of the <code>Configured</code> calls
36+
* the {@link #setConf(Configuration)} method, which will call into the
37+
* subclasses before they have been fully constructed.
38+
*
39+
*/
40+
@InterfaceAudience.Public
41+
@InterfaceStability.Evolving
42+
public abstract class AbstractDNSToSwitchMapping
43+
implements DNSToSwitchMapping, Configurable {
44+
45+
private Configuration conf;
46+
47+
/**
48+
* Create an unconfigured instance
49+
*/
50+
protected AbstractDNSToSwitchMapping() {
51+
}
52+
53+
/**
54+
* Create an instance, caching the configuration file.
55+
* This constructor does not call {@link #setConf(Configuration)}; if
56+
* a subclass extracts information in that method, it must call it explicitly.
57+
* @param conf the configuration
58+
*/
59+
protected AbstractDNSToSwitchMapping(Configuration conf) {
60+
this.conf = conf;
61+
}
62+
63+
@Override
64+
public Configuration getConf() {
65+
return conf;
66+
}
67+
68+
@Override
69+
public void setConf(Configuration conf) {
70+
this.conf = conf;
71+
}
72+
73+
/**
74+
* Predicate that indicates that the switch mapping is known to be
75+
* single-switch. The base class returns false: it assumes all mappings are
76+
* multi-rack. Subclasses may override this with methods that are more aware
77+
* of their topologies.
78+
*
79+
* <p/>
80+
*
81+
* This method is used when parts of Hadoop need know whether to apply
82+
* single rack vs multi-rack policies, such as during block placement.
83+
* Such algorithms behave differently if they are on multi-switch systems.
84+
* </p>
85+
*
86+
* @return true if the mapping thinks that it is on a single switch
87+
*/
88+
public boolean isSingleSwitch() {
89+
return false;
90+
}
91+
92+
/**
93+
* Query for a {@link DNSToSwitchMapping} instance being on a single
94+
* switch.
95+
* <p/>
96+
* This predicate simply assumes that all mappings not derived from
97+
* this class are multi-switch.
98+
* @param mapping the mapping to query
99+
* @return true if the base class says it is single switch, or the mapping
100+
* is not derived from this class.
101+
*/
102+
public static boolean isMappingSingleSwitch(DNSToSwitchMapping mapping) {
103+
return mapping instanceof AbstractDNSToSwitchMapping
104+
&& ((AbstractDNSToSwitchMapping) mapping).isSingleSwitch();
105+
}
106+
107+
}

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/CachedDNSToSwitchMapping.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@
3434
*/
3535
@InterfaceAudience.Public
3636
@InterfaceStability.Evolving
37-
public class CachedDNSToSwitchMapping implements DNSToSwitchMapping {
37+
public class CachedDNSToSwitchMapping extends AbstractDNSToSwitchMapping {
3838
private Map<String, String> cache = new ConcurrentHashMap<String, String>();
39-
protected DNSToSwitchMapping rawMapping;
39+
40+
/**
41+
* The uncached mapping
42+
*/
43+
protected final DNSToSwitchMapping rawMapping;
4044

4145
/**
4246
* cache a raw DNS mapping
@@ -118,4 +122,14 @@ public List<String> resolve(List<String> names) {
118122
return getCachedHosts(names);
119123

120124
}
125+
126+
/**
127+
* Delegate the switch topology query to the raw mapping, via
128+
* {@link AbstractDNSToSwitchMapping#isMappingSingleSwitch(DNSToSwitchMapping)}
129+
* @return true iff the raw mapper is considered single-switch.
130+
*/
131+
@Override
132+
public boolean isSingleSwitch() {
133+
return isMappingSingleSwitch(rawMapping);
134+
}
121135
}

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/DNSToSwitchMapping.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public interface DNSToSwitchMapping {
4040
* Note the hostname/ip-address is not part of the returned path.
4141
* The network topology of the cluster would determine the number of
4242
* components in the network path.
43+
* <p/>
44+
*
45+
* If a name cannot be resolved to a rack, the implementation
46+
* should return {@link NetworkTopology#DEFAULT_RACK}. This
47+
* is what the bundled implementations do, though it is not a formal requirement
48+
*
4349
* @param names the list of hosts to resolve (can be empty)
4450
* @return list of resolved network paths.
4551
* If <i>names</i> is empty, the returned list is also empty

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/ScriptBasedMapping.java

Lines changed: 98 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,21 @@
3232

3333
/**
3434
* This class implements the {@link DNSToSwitchMapping} interface using a
35-
* script configured via the {@link CommonConfigurationKeys#NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY}
35+
* script configured via the
36+
* {@link CommonConfigurationKeys#NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY} option.
37+
* <p/>
38+
* It contains a static class <code>RawScriptBasedMapping</code> that performs
39+
* the work: reading the configuration parameters, executing any defined
40+
* script, handling errors and such like. The outer
41+
* class extends {@link CachedDNSToSwitchMapping} to cache the delegated
42+
* queries.
43+
* <p/>
44+
* This DNS mapper's {@link #isSingleSwitch()} predicate returns
45+
* true if and only if a script is defined.
3646
*/
3747
@InterfaceAudience.Public
3848
@InterfaceStability.Evolving
39-
public final class ScriptBasedMapping extends CachedDNSToSwitchMapping
40-
implements Configurable
41-
{
42-
public ScriptBasedMapping() {
43-
super(new RawScriptBasedMapping());
44-
}
49+
public final class ScriptBasedMapping extends CachedDNSToSwitchMapping {
4550

4651
/**
4752
* Minimum number of arguments: {@value}
@@ -65,6 +70,18 @@ public ScriptBasedMapping() {
6570
static final String SCRIPT_ARG_COUNT_KEY =
6671
CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_NUMBER_ARGS_KEY ;
6772

73+
/**
74+
* Create an instance with the default configuration.
75+
* </p>
76+
* Calling {@link #setConf(Configuration)} will trigger a
77+
* re-evaluation of the configuration settings and so be used to
78+
* set up the mapping script.
79+
*
80+
*/
81+
public ScriptBasedMapping() {
82+
super(new RawScriptBasedMapping());
83+
}
84+
6885
/**
6986
* Create an instance from the given configuration
7087
* @param conf configuration
@@ -74,44 +91,58 @@ public ScriptBasedMapping(Configuration conf) {
7491
setConf(conf);
7592
}
7693

94+
/**
95+
* Get the cached mapping and convert it to its real type
96+
* @return the inner raw script mapping.
97+
*/
98+
private RawScriptBasedMapping getRawMapping() {
99+
return (RawScriptBasedMapping)rawMapping;
100+
}
101+
77102
@Override
78103
public Configuration getConf() {
79-
return ((RawScriptBasedMapping)rawMapping).getConf();
104+
return getRawMapping().getConf();
80105
}
81106

107+
/**
108+
* {@inheritDoc}
109+
* <p/>
110+
* This will get called in the superclass constructor, so a check is needed
111+
* to ensure that the raw mapping is defined before trying to relaying a null
112+
* configuration.
113+
* @param conf
114+
*/
82115
@Override
83116
public void setConf(Configuration conf) {
84-
((RawScriptBasedMapping)rawMapping).setConf(conf);
117+
super.setConf(conf);
118+
getRawMapping().setConf(conf);
85119
}
86120

87121
/**
88122
* This is the uncached script mapping that is fed into the cache managed
89123
* by the superclass {@link CachedDNSToSwitchMapping}
90124
*/
91125
private static final class RawScriptBasedMapping
92-
implements DNSToSwitchMapping {
126+
extends AbstractDNSToSwitchMapping {
93127
private String scriptName;
94-
private Configuration conf;
95128
private int maxArgs; //max hostnames per call of the script
96-
private static Log LOG =
129+
private static final Log LOG =
97130
LogFactory.getLog(ScriptBasedMapping.class);
98131

99132
/**
100-
* Set the configuration and
101-
* @param conf extract the configuration parameters of interest
133+
* Set the configuration and extract the configuration parameters of interest
134+
* @param conf the new configuration
102135
*/
136+
@Override
103137
public void setConf (Configuration conf) {
104-
this.scriptName = conf.get(SCRIPT_FILENAME_KEY);
105-
this.maxArgs = conf.getInt(SCRIPT_ARG_COUNT_KEY, DEFAULT_ARG_COUNT);
106-
this.conf = conf;
107-
}
108-
109-
/**
110-
* Get the configuration
111-
* @return the configuration
112-
*/
113-
public Configuration getConf () {
114-
return conf;
138+
super.setConf(conf);
139+
if (conf != null) {
140+
scriptName = conf.get(SCRIPT_FILENAME_KEY);
141+
maxArgs = conf.getInt(SCRIPT_ARG_COUNT_KEY, DEFAULT_ARG_COUNT);
142+
} else {
143+
scriptName = null;
144+
maxArgs = 0;
145+
}
115146
}
116147

117148
/**
@@ -122,42 +153,42 @@ public RawScriptBasedMapping() {}
122153

123154
@Override
124155
public List<String> resolve(List<String> names) {
125-
List <String> m = new ArrayList<String>(names.size());
126-
127-
if (names.isEmpty()) {
128-
return m;
129-
}
156+
List<String> m = new ArrayList<String>(names.size());
130157

131-
if (scriptName == null) {
132-
for (int i = 0; i < names.size(); i++) {
133-
m.add(NetworkTopology.DEFAULT_RACK);
158+
if (names.isEmpty()) {
159+
return m;
134160
}
135-
return m;
136-
}
137-
138-
String output = runResolveCommand(names);
139-
if (output != null) {
140-
StringTokenizer allSwitchInfo = new StringTokenizer(output);
141-
while (allSwitchInfo.hasMoreTokens()) {
142-
String switchInfo = allSwitchInfo.nextToken();
143-
m.add(switchInfo);
161+
162+
if (scriptName == null) {
163+
for (String name : names) {
164+
m.add(NetworkTopology.DEFAULT_RACK);
165+
}
166+
return m;
144167
}
145-
146-
if (m.size() != names.size()) {
147-
// invalid number of entries returned by the script
148-
LOG.error("Script " + scriptName + " returned "
149-
+ Integer.toString(m.size()) + " values when "
150-
+ Integer.toString(names.size()) + " were expected.");
168+
169+
String output = runResolveCommand(names);
170+
if (output != null) {
171+
StringTokenizer allSwitchInfo = new StringTokenizer(output);
172+
while (allSwitchInfo.hasMoreTokens()) {
173+
String switchInfo = allSwitchInfo.nextToken();
174+
m.add(switchInfo);
175+
}
176+
177+
if (m.size() != names.size()) {
178+
// invalid number of entries returned by the script
179+
LOG.error("Script " + scriptName + " returned "
180+
+ Integer.toString(m.size()) + " values when "
181+
+ Integer.toString(names.size()) + " were expected.");
182+
return null;
183+
}
184+
} else {
185+
// an error occurred. return null to signify this.
186+
// (exn was already logged in runResolveCommand)
151187
return null;
152188
}
153-
} else {
154-
// an error occurred. return null to signify this.
155-
// (exn was already logged in runResolveCommand)
156-
return null;
189+
190+
return m;
157191
}
158-
159-
return m;
160-
}
161192

162193
/**
163194
* Build and execute the resolution command. The command is
@@ -195,10 +226,10 @@ private String runResolveCommand(List<String> args) {
195226
dir = new File(userDir);
196227
}
197228
ShellCommandExecutor s = new ShellCommandExecutor(
198-
cmdList.toArray(new String[0]), dir);
229+
cmdList.toArray(new String[cmdList.size()]), dir);
199230
try {
200231
s.execute();
201-
allOutput.append(s.getOutput() + " ");
232+
allOutput.append(s.getOutput()).append(" ");
202233
} catch (Exception e) {
203234
LOG.warn("Exception: ", e);
204235
return null;
@@ -207,5 +238,15 @@ private String runResolveCommand(List<String> args) {
207238
}
208239
return allOutput.toString();
209240
}
241+
242+
/**
243+
* Declare that the mapper is single-switched if a script was not named
244+
* in the configuration.
245+
* @return true iff there is no script
246+
*/
247+
@Override
248+
public boolean isSingleSwitch() {
249+
return scriptName == null;
250+
}
210251
}
211252
}

0 commit comments

Comments
 (0)