This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: Caching of IP address lookups
- From: Michael Koch <konqueror at gmx dot de>
- To: java-patches at gcc dot gnu dot org
- Date: Sat, 20 Mar 2004 21:49:28 +0100
- Subject: Patch: Caching of IP address lookups
Hi list,
I merged the code in classpath's java.net.InetAddress that handles
caching of lookup results.
Please review and comment. Okay for trunk ?
Michael
2004-03-20 Michael Koch <konqueror@gmx.de>
* java/net/InetAddress.java
(DEFAULT_CACHE_SIZE): New constant.
(DEFAULT_CACHE_PERIOD): Likewise.
(DEFAULT_CACHE_PURGE_PCT): Likewise.
(cache_size): New static field.
(cache_period): Likewise.
(cache_purge_pct): Likewise.
(cache): Likewise.
(static): Initialize cache_size, cache_period and cache_purge_pct.
(lookup_time): New field.
(InetAddress): Initialize lookup_time.
(getAllByName): Check cache before trying to lookup an address.
Add found addresses to cache.
(checkForCache): New method.
(addToCache): Likewise.
Index: java/net/InetAddress.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/InetAddress.java,v
retrieving revision 1.28
diff -u -b -B -r1.28 InetAddress.java
--- java/net/InetAddress.java 20 Mar 2004 17:59:39 -0000 1.28
+++ java/net/InetAddress.java 20 Mar 2004 20:46:14 -0000
@@ -44,6 +44,7 @@
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.util.HashMap;
/**
* This class models an Internet address. It does not have a public
@@ -65,12 +66,51 @@
private static final long serialVersionUID = 3286316764910316507L;
/**
+ * The default DNS hash table size,
+ * Use a prime number happy with hash table.
+ */
+ private static final int DEFAULT_CACHE_SIZE = 89;
+
+ /**
+ * The default caching period in minutes.
+ */
+ private static final int DEFAULT_CACHE_PERIOD = (4 * 60);
+
+ /**
+ * Percentage of cache entries to purge when the table gets full.
+ */
+ private static final int DEFAULT_CACHE_PURGE_PCT = 30;
+
+ /**
* Dummy InetAddress, used to bind socket to any (all) network interfaces.
*/
static InetAddress ANY_IF;
+ /**
+ * The size of the cache.
+ */
+ private static int cache_size = 0;
+
+ /**
+ * The length of time we will continue to read the address from cache
+ * before forcing another lookup.
+ */
+ private static int cache_period = 0;
+
+ /**
+ * What percentage of the cache we will purge if it gets full.
+ */
+ private static int cache_purge_pct = 0;
+
+ /**
+ * HashMap to use as DNS lookup cache.
+ * Use HashMap because all accesses to cache are already synchronized.
+ */
+ private static HashMap cache;
+
private static final byte[] localhostAddress = { 127, 0, 0, 1 };
+ // Cache for localhost.
private static InetAddress localhost = null;
static
@@ -81,6 +121,25 @@
System.loadLibrary ("javanet");
}
+ // Look for properties that override default caching behavior
+ cache_size = Integer.getInteger ("gnu.java.net.dns_cache_size",
+ DEFAULT_CACHE_SIZE).intValue();
+ cache_period = Integer.getInteger ("gnu.java.net.dns_cache_period",
+ DEFAULT_CACHE_PERIOD * 60
+ * 1000).intValue();
+
+ cache_purge_pct = Integer.getInteger ("gnu.java.net.dns_cache_purge_pct",
+ DEFAULT_CACHE_PURGE_PCT).
+ intValue ();
+
+ // Fallback to defaults if necessary
+ if ((cache_purge_pct < 1) || (cache_purge_pct > 100))
+ cache_purge_pct = DEFAULT_CACHE_PURGE_PCT;
+
+ // Create the cache
+ if (cache_size != 0)
+ cache = new HashMap (cache_size);
+
byte[] zeros = { 0, 0, 0, 0 };
ANY_IF = new InetAddress (zeros, "0.0.0.0");
}
@@ -103,6 +162,11 @@
String hostName;
/**
+ * The time this address was looked up.
+ */
+ transient long lookup_time;
+
+ /**
* The field 'family' seems to be the AF_ value.
* FIXME: Much of the code in the other java.net classes does not make
* use of this family field. A better implementation would be to make
@@ -138,6 +202,8 @@
if (address != null)
family = getFamily (address);
+
+ lookup_time = System.currentTimeMillis();
}
/**
@@ -622,6 +688,7 @@
// Try to resolve the host by DNS
InetAddress[] addresses = getAllByName (hostname);
+ addToCache(hostname, addresses);
return addresses [0];
}
@@ -649,6 +716,14 @@
if (s != null)
s.checkConnect (hostname, -1);
+ // Check the cache for this host before doing a lookup
+ InetAddress[] addresses = checkCacheFor (hostname);
+
+ if (addresses != null)
+ return addresses;
+
+ // Not in cache, try the lookup
+
// Check if hostname is an IP address
byte[] address = aton (hostname);
if (address != null)
@@ -659,7 +734,70 @@
}
// Try to resolve the hostname by DNS
- return lookup (hostname, null, true);
+ addresses = lookup (hostname, null, true);
+ addToCache (hostname, addresses);
+ return addresses;
+ }
+
+ /**
+ * This method checks the DNS cache to see if we have looked this hostname
+ * up before. If so, we return the cached addresses unless it has been in the
+ * cache too long.
+ *
+ * @param hostname The hostname to check for
+ *
+ * @return The InetAddress for this hostname or null if not available
+ */
+ private static synchronized InetAddress[] checkCacheFor (String hostname)
+ {
+ InetAddress[]addresses = null;
+
+ if (cache_size == 0)
+ return (null);
+
+ Object obj = cache.get (hostname);
+ if (obj == null)
+ return (null);
+
+ if (obj instanceof InetAddress[])
+ addresses = (InetAddress[])obj;
+
+ if (addresses == null)
+ return (null);
+
+ if (cache_period != -1)
+ if ((System.currentTimeMillis () - addresses[0].lookup_time) >
+ cache_period)
+ {
+ cache.remove (hostname);
+ return (null);
+ }
+
+ return addresses;
+ }
+
+ /**
+ * This method adds an InetAddress object to our DNS cache. Note that
+ * if the cache is full, then we run a purge to get rid of old entries.
+ * This will cause a performance hit, thus applications using lots of
+ * lookups should set the cache size to be very large.
+ *
+ * @param hostname The hostname to cache this address under
+ * @param obj The InetAddress or InetAddress array to store
+ */
+ private static synchronized void addToCache (String hostname, Object obj)
+ {
+ if (cache_size == 0)
+ return;
+
+ // Check to see if hash table is full
+ if (cache_size != -1)
+ if (cache.size () == cache_size)
+ {
+ // FIXME Add code to purge later.
+ }
+
+ cache.put (hostname, obj);
}
/**