This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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);
   }
 
   /**

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]