Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package java.net;
     18 
     19 import libcore.util.BasicLruCache;
     20 
     21 /**
     22  * Implements caching for {@code InetAddress}. We use a unified cache for both positive and negative
     23  * cache entries.
     24  *
     25  * TODO: benchmark and optimize InetAddress until we get to the point where we can just rely on
     26  * the C library level caching. The main thing caching at this level buys us is avoiding repeated
     27  * conversions from 'struct sockaddr's to InetAddress[].
     28  */
     29 class AddressCache {
     30     /**
     31      * When the cache contains more entries than this, we start dropping the oldest ones.
     32      * This should be a power of two to avoid wasted space in our custom map.
     33      */
     34     private static final int MAX_ENTRIES = 16;
     35 
     36     // The TTL for the Java-level cache is short, just 2s.
     37     private static final long TTL_NANOS = 2 * 1000000000L;
     38 
     39     // The actual cache.
     40     private final BasicLruCache<String, AddressCacheEntry> cache
     41             = new BasicLruCache<String, AddressCacheEntry>(MAX_ENTRIES);
     42 
     43     static class AddressCacheEntry {
     44         // Either an InetAddress[] for a positive entry,
     45         // or a String detail message for a negative entry.
     46         final Object value;
     47 
     48         /**
     49          * The absolute expiry time in nanoseconds. Nanoseconds from System.nanoTime is ideal
     50          * because -- unlike System.currentTimeMillis -- it can never go backwards.
     51          *
     52          * We don't need to worry about overflow with a TTL_NANOS of 2s.
     53          */
     54         final long expiryNanos;
     55 
     56         AddressCacheEntry(Object value) {
     57             this.value = value;
     58             this.expiryNanos = System.nanoTime() + TTL_NANOS;
     59         }
     60     }
     61 
     62     /**
     63      * Removes all entries from the cache.
     64      */
     65     public void clear() {
     66         cache.evictAll();
     67     }
     68 
     69     /**
     70      * Returns the cached InetAddress[] associated with 'hostname'. Returns null if nothing is known
     71      * about 'hostname'. Returns a String suitable for use as an UnknownHostException detail
     72      * message if 'hostname' is known not to exist.
     73      */
     74     public Object get(String hostname) {
     75         AddressCacheEntry entry = cache.get(hostname);
     76         // Do we have a valid cache entry?
     77         if (entry != null && entry.expiryNanos >= System.nanoTime()) {
     78             return entry.value;
     79         }
     80         // Either we didn't find anything, or it had expired.
     81         // No need to remove expired entries: the caller will provide a replacement shortly.
     82         return null;
     83     }
     84 
     85     /**
     86      * Associates the given 'addresses' with 'hostname'. The association will expire after a
     87      * certain length of time.
     88      */
     89     public void put(String hostname, InetAddress[] addresses) {
     90         cache.put(hostname, new AddressCacheEntry(addresses));
     91     }
     92 
     93     /**
     94      * Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
     95      * negative cache entry.)
     96      */
     97     public void putUnknownHost(String hostname, String detailMessage) {
     98         cache.put(hostname, new AddressCacheEntry(detailMessage));
     99     }
    100 }
    101