OSDN Git Service

Add a missing "static", found by FindBugs.
[android-x86/dalvik.git] / libcore / luni / src / main / java / java / net / AddressCache.java
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 java.security.AccessController;
20 import java.util.LinkedHashMap;
21 import java.util.Map;
22
23 import org.apache.harmony.luni.util.PriviAction;
24
25 /**
26  * Implements caching for {@code InetAddress}. We use a unified cache for both positive and negative
27  * cache entries.
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 = 512;
35     
36     // This isn't used by our HashMap implementation, but the API demands it.
37     private static final float DEFAULT_LOAD_FACTOR = .75F;
38     
39     // Default time-to-live for positive cache entries. 600 seconds (10 minutes).
40     private static final long DEFAULT_POSITIVE_TTL_NANOS = 600 * 1000000000L;
41     // Default time-to-live for negative cache entries. 10 seconds.
42     private static final long DEFAULT_NEGATIVE_TTL_NANOS = 10 * 1000000000L;
43     
44     // Failed lookups are represented in the cache my mappings to this empty array.
45     private static final InetAddress[] NO_ADDRESSES = new InetAddress[0];
46     
47     // The actual cache.
48     private final Map<String, AddressCacheEntry> map;
49     
50     static class AddressCacheEntry {
51         // The addresses. May be the empty array for a negative cache entry.
52         InetAddress[] addresses;
53         
54         /**
55          * The absolute expiry time in nanoseconds. Nanoseconds from System.nanoTime is ideal
56          * because -- unlike System.currentTimeMillis -- it can never go backwards.
57          * 
58          * Unless we need to cope with DNS TTLs of 292 years, we don't need to worry about overflow.
59          */
60         long expiryNanos;
61         
62         AddressCacheEntry(InetAddress[] addresses, long expiryNanos) {
63             this.addresses = addresses;
64             this.expiryNanos = expiryNanos;
65         }
66     }
67     
68     public AddressCache() {
69         // We pass 'true' so removeEldestEntry removes the least-recently accessed entry, rather
70         // than the least-recently inserted.
71         map = new LinkedHashMap<String, AddressCacheEntry>(0, DEFAULT_LOAD_FACTOR, true) {
72             @Override protected boolean removeEldestEntry(Entry<String, AddressCacheEntry> eldest) {
73                 // By the time this method is called, the new entry has already been inserted and
74                 // the map will have grown to accommodate it. Using == lets us prevent resizing.
75                 return size() == MAX_ENTRIES;
76             }
77         };
78     }
79     
80     /**
81      * Returns the cached addresses associated with 'hostname'. Returns null if nothing is known
82      * about 'hostname'. Returns an empty array if 'hostname' is known not to exist.
83      */
84     public InetAddress[] get(String hostname) {
85         AddressCacheEntry entry;
86         synchronized (map) {
87             entry = map.get(hostname);
88         }
89         // Do we have a valid cache entry?
90         if (entry != null && entry.expiryNanos >= System.nanoTime()) {
91             return entry.addresses;
92         }
93         // Either we didn't find anything, or it had expired.
94         // No need to remove expired entries: the caller will provide a replacement shortly.
95         return null;
96     }
97     
98     /**
99      * Associates the given 'addresses' with 'hostname'. The association will expire after a
100      * certain length of time.
101      */
102     public void put(String hostname, InetAddress[] addresses) {
103         // Calculate the expiry time.
104         boolean isPositive = (addresses.length > 0);
105         String propertyName = isPositive ? "networkaddress.cache.ttl" : "networkaddress.cache.negative.ttl";
106         long defaultTtlNanos = isPositive ? DEFAULT_POSITIVE_TTL_NANOS : DEFAULT_NEGATIVE_TTL_NANOS;
107         // Fast-path the default case...
108         long expiryNanos = System.nanoTime() + defaultTtlNanos;
109         if (System.getSecurityManager() != null || System.getProperty(propertyName, null) != null) {
110             // ...and let those using a SecurityManager or custom properties pay full price.
111             expiryNanos = customTtl(propertyName, defaultTtlNanos);
112             if (expiryNanos == Long.MIN_VALUE) {
113                 return;
114             }
115         }
116         // Update the cache.
117         synchronized (map) {
118             map.put(hostname, new AddressCacheEntry(addresses, expiryNanos));
119         }
120     }
121     
122     /**
123      * Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
124      * negative cache entry.)
125      */
126     public void putUnknownHost(String hostname) {
127         put(hostname, NO_ADDRESSES);
128     }
129     
130     private long customTtl(String propertyName, long defaultTtlNanos) {
131         String ttlString = AccessController.doPrivileged(new PriviAction<String>(propertyName, null));
132         if (ttlString == null) {
133             return System.nanoTime() + defaultTtlNanos;
134         }
135         try {
136             long ttlS = Long.parseLong(ttlString);
137             // For the system properties, -1 means "cache forever" and 0 means "don't cache".
138             if (ttlS == -1) {
139                 return Long.MAX_VALUE;
140             } else if (ttlS == 0) {
141                 return Long.MIN_VALUE;
142             } else {
143                 return System.nanoTime() + ttlS * 1000000000L;
144             }
145         } catch (NumberFormatException ex) {
146             return System.nanoTime() + defaultTtlNanos;
147         }
148     }
149 }