    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.List;
    022    import java.util.Map;
    023    import java.util.concurrent.ConcurrentHashMap;
    024
    025    import org.apache.hadoop.classification.InterfaceAudience;
    026    import org.apache.hadoop.classification.InterfaceStability;
    027
    028    /**
    029     * A cached implementation of DNSToSwitchMapping that takes an
    030     * raw DNSToSwitchMapping and stores the resolved network location in
    031     * a cache. The following calls to a resolved network location
    032     * will get its location from the cache.
    033     *
    034     */
    035    @InterfaceAudience.Public
    036    @InterfaceStability.Evolving
    037    public class CachedDNSToSwitchMapping extends AbstractDNSToSwitchMapping {
    038      private Map<String, String> cache = new ConcurrentHashMap<String, String>();
    039
    040      /**
    041       * The uncached mapping
    042       */
    043      protected final DNSToSwitchMapping rawMapping;
    044
    045      /**
    046       * cache a raw DNS mapping
    047       * @param rawMapping the raw mapping to cache
    048       */
    049      public CachedDNSToSwitchMapping(DNSToSwitchMapping rawMapping) {
    050        this.rawMapping = rawMapping;
    051      }
    052
    053      /**
    054       * @param names a list of hostnames to probe for being cached
    055       * @return the hosts from 'names' that have not been cached previously
    056       */
    057      private List<String> getUncachedHosts(List<String> names) {
    058        // find out all names without cached resolved location
    059        List<String> unCachedHosts = new ArrayList<String>(names.size());
    060        for (String name : names) {
    061          if (cache.get(name) == null) {
    062            unCachedHosts.add(name);
    063          }
    064        }
    065        return unCachedHosts;
    066      }
    067
    068      /**
    069       * Caches the resolved host:rack mappings. The two list
    070       * parameters must be of equal size.
    071       *
    072       * @param uncachedHosts a list of hosts that were uncached
    073       * @param resolvedHosts a list of resolved host entries where the element
    074       * at index(i) is the resolved value for the entry in uncachedHosts[i]
    075       */
    076      private void cacheResolvedHosts(List<String> uncachedHosts,
    077          List<String> resolvedHosts) {
    078        // Cache the result
    079        if (resolvedHosts != null) {
    080          for (int i=0; i<uncachedHosts.size(); i++) {
    081            cache.put(uncachedHosts.get(i), resolvedHosts.get(i));
    082          }
    083        }
    084      }
    085
    086      /**
    087       * @param names a list of hostnames to look up (can be be empty)
    088       * @return the cached resolution of the list of hostnames/addresses.
    089       *  or null if any of the names are not currently in the cache
    090       */
    091      private List<String> getCachedHosts(List<String> names) {
    092        List<String> result = new ArrayList<String>(names.size());
    093        // Construct the result
    094        for (String name : names) {
    095          String networkLocation = cache.get(name);
    096          if (networkLocation != null) {
    097            result.add(networkLocation);
    098          } else {
    099            return null;
    100          }
    101        }
    102        return result;
    103      }
    104
    105      @Override
    106      public List<String> resolve(List<String> names) {
    107        // normalize all input names to be in the form of IP addresses
    108        names = NetUtils.normalizeHostNames(names);
    109
    110        List <String> result = new ArrayList<String>(names.size());
    111        if (names.isEmpty()) {
    112          return result;
    113        }
    114
    115        List<String> uncachedHosts = getUncachedHosts(names);
    116
    117        // Resolve the uncached hosts
    118        List<String> resolvedHosts = rawMapping.resolve(uncachedHosts);
    119        //cache them
    120        cacheResolvedHosts(uncachedHosts, resolvedHosts);
    121        //now look up the entire list in the cache
    122        return getCachedHosts(names);
    123
    124      }
    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      }
    135    }