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 package org.apache.hadoop.net;
019
020 import java.util.ArrayList;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.concurrent.ConcurrentHashMap;
025
026 import org.apache.hadoop.classification.InterfaceAudience;
027 import org.apache.hadoop.classification.InterfaceStability;
028
029 /**
030 * A cached implementation of DNSToSwitchMapping that takes an
031 * raw DNSToSwitchMapping and stores the resolved network location in
032 * a cache. The following calls to a resolved network location
033 * will get its location from the cache.
034 *
035 */
036 @InterfaceAudience.Public
037 @InterfaceStability.Evolving
038 public class CachedDNSToSwitchMapping extends AbstractDNSToSwitchMapping {
039 private Map<String, String> cache = new ConcurrentHashMap<String, String>();
040
041 /**
042 * The uncached mapping
043 */
044 protected final DNSToSwitchMapping rawMapping;
045
046 /**
047 * cache a raw DNS mapping
048 * @param rawMapping the raw mapping to cache
049 */
050 public CachedDNSToSwitchMapping(DNSToSwitchMapping rawMapping) {
051 this.rawMapping = rawMapping;
052 }
053
054 /**
055 * @param names a list of hostnames to probe for being cached
056 * @return the hosts from 'names' that have not been cached previously
057 */
058 private List<String> getUncachedHosts(List<String> names) {
059 // find out all names without cached resolved location
060 List<String> unCachedHosts = new ArrayList<String>(names.size());
061 for (String name : names) {
062 if (cache.get(name) == null) {
063 unCachedHosts.add(name);
064 }
065 }
066 return unCachedHosts;
067 }
068
069 /**
070 * Caches the resolved host:rack mappings. The two list
071 * parameters must be of equal size.
072 *
073 * @param uncachedHosts a list of hosts that were uncached
074 * @param resolvedHosts a list of resolved host entries where the element
075 * at index(i) is the resolved value for the entry in uncachedHosts[i]
076 */
077 private void cacheResolvedHosts(List<String> uncachedHosts,
078 List<String> resolvedHosts) {
079 // Cache the result
080 if (resolvedHosts != null) {
081 for (int i=0; i<uncachedHosts.size(); i++) {
082 cache.put(uncachedHosts.get(i), resolvedHosts.get(i));
083 }
084 }
085 }
086
087 /**
088 * @param names a list of hostnames to look up (can be be empty)
089 * @return the cached resolution of the list of hostnames/addresses.
090 * or null if any of the names are not currently in the cache
091 */
092 private List<String> getCachedHosts(List<String> names) {
093 List<String> result = new ArrayList<String>(names.size());
094 // Construct the result
095 for (String name : names) {
096 String networkLocation = cache.get(name);
097 if (networkLocation != null) {
098 result.add(networkLocation);
099 } else {
100 return null;
101 }
102 }
103 return result;
104 }
105
106 @Override
107 public List<String> resolve(List<String> names) {
108 // normalize all input names to be in the form of IP addresses
109 names = NetUtils.normalizeHostNames(names);
110
111 List <String> result = new ArrayList<String>(names.size());
112 if (names.isEmpty()) {
113 return result;
114 }
115
116 List<String> uncachedHosts = getUncachedHosts(names);
117
118 // Resolve the uncached hosts
119 List<String> resolvedHosts = rawMapping.resolve(uncachedHosts);
120 //cache them
121 cacheResolvedHosts(uncachedHosts, resolvedHosts);
122 //now look up the entire list in the cache
123 return getCachedHosts(names);
124
125 }
126
127 /**
128 * Get the (host x switch) map.
129 * @return a copy of the cached map of hosts to rack
130 */
131 @Override
132 public Map<String, String> getSwitchMap() {
133 Map<String, String > switchMap = new HashMap<String, String>(cache);
134 return switchMap;
135 }
136
137
138 @Override
139 public String toString() {
140 return "cached switch mapping relaying to " + rawMapping;
141 }
142
143 /**
144 * Delegate the switch topology query to the raw mapping, via
145 * {@link AbstractDNSToSwitchMapping#isMappingSingleSwitch(DNSToSwitchMapping)}
146 * @return true iff the raw mapper is considered single-switch.
147 */
148 @Override
149 public boolean isSingleSwitch() {
150 return isMappingSingleSwitch(rawMapping);
151 }
152
153 @Override
154 public void reloadCachedMappings() {
155 cache.clear();
156 }
157
158 @Override
159 public void reloadCachedMappings(List<String> names) {
160 for (String name : names) {
161 cache.remove(name);
162 }
163 }
164 }