hello all,

the attached patch --already committed-- fixes the above PR by having the 
cache of previously resolved resource bundles as an LRU, of CACHE_SIZE 
elements, organized by access.


2006-08-13  Raif S. Naffah  <[EMAIL PROTECTED]>

        PR Classpath/23952
        * java/util/ResourceBundle.java (CACHE_SIZE): New constant.
        (bundleCache): Replaced with an LRU of CACHE_SIZE elements.
        (lastDefaultLocale): Removed.
        (emptyLocale): Likewise.
        (BundleKey.defaultLocale): New field.
        (BundleKey.BundleKey): Add a Locale (as a 1st positional) argument.
        (BundleKey.set): Likewise.
        (BundleKey.equals): Take defaultLocal field into consideration.
        (getBundle(String, Locale, ClassLoader)): Use updated BundleKey and LRU.


cheers;
rsn
Index: ResourceBundle.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/util/ResourceBundle.java,v
retrieving revision 1.37
diff -u -r1.37 ResourceBundle.java
--- ResourceBundle.java	1 Mar 2006 12:14:24 -0000	1.37
+++ ResourceBundle.java	13 Aug 2006 00:45:37 -0000
@@ -91,6 +91,14 @@
 public abstract class ResourceBundle
 {
   /**
+   * Maximum size of our cache of <code>ResourceBundle</code>s keyed by
+   * [EMAIL PROTECTED] BundleKey} instances.
+   *
+   * @see BundleKey
+   */
+  private static final int CACHE_SIZE = 100;
+
+  /**
    * The parent bundle. This is consulted when you call getObject and there
    * is no such resource in the current bundle. This field may be null.
    */
@@ -104,21 +112,22 @@
   private Locale locale;

   /**
-   * The resource bundle cache.
-   */
-  private static Map bundleCache;
-
-  /**
-   * The last default Locale we saw. If this ever changes then we have to
-   * reset our caches.
-   */
-  private static Locale lastDefaultLocale;
-
-  /**
-   * The `empty' locale is created once in order to optimize
-   * tryBundle().
+   * A VM-wide cache of resource bundles already fetched.
+   * <p>
+   * This [EMAIL PROTECTED] Map} is a Least Recently Used (LRU) cache, of the last
+   * [EMAIL PROTECTED] #CACHE_SIZE} accessed <code>ResourceBundle</code>s keyed by the
+   * tuple: default locale, resource-bundle name, resource-bundle locale, and
+   * classloader.
+   *
+   * @see BundleKey
    */
-  private static final Locale emptyLocale = new Locale("");
+  private static Map bundleCache = new LinkedHashMap(CACHE_SIZE + 1, 0.75F, true)
+  {
+    public boolean removeEldestEntry(Map.Entry entry)
+    {
+      return size() > CACHE_SIZE;
+    }
+  };

   /**
    * The constructor. It does nothing special.
@@ -246,6 +255,7 @@
       by the combination of bundle name, locale, and class loader. */
   private static class BundleKey
   {
+    Locale defaultLocale;
     String baseName;
     Locale locale;
     ClassLoader classLoader;
@@ -253,18 +263,19 @@

     BundleKey() {}

-    BundleKey(String s, Locale l, ClassLoader cl)
+    BundleKey(Locale dl, String s, Locale l, ClassLoader cl)
     {
-      set(s, l, cl);
+      set(dl, s, l, cl);
     }

-    void set(String s, Locale l, ClassLoader cl)
+    void set(Locale dl, String s, Locale l, ClassLoader cl)
     {
+      defaultLocale = dl;
       baseName = s;
       locale = l;
       classLoader = cl;
-      hashcode = baseName.hashCode() ^ locale.hashCode() ^
-        classLoader.hashCode();
+      hashcode = defaultLocale.hashCode() ^ baseName.hashCode()
+          ^ locale.hashCode() ^ classLoader.hashCode();
     }

     public int hashCode()
@@ -277,10 +288,11 @@
       if (! (o instanceof BundleKey))
         return false;
       BundleKey key = (BundleKey) o;
-      return hashcode == key.hashcode &&
-	baseName.equals(key.baseName) &&
-        locale.equals(key.locale) &&
-	classLoader.equals(key.classLoader);
+      return hashcode == key.hashcode
+          && defaultLocale.equals(key.defaultLocale)
+          && baseName.equals(key.baseName)
+          && locale.equals(key.locale)
+          && classLoader.equals(key.classLoader);
     }
   }

@@ -370,61 +382,39 @@
   public static synchronized ResourceBundle getBundle
     (String baseName, Locale locale, ClassLoader classLoader)
   {
-    // If the default locale changed since the last time we were called,
-    // all cache entries are invalidated.
     Locale defaultLocale = Locale.getDefault();
-    if (defaultLocale != lastDefaultLocale)
-      {
-	bundleCache = new HashMap();
-	lastDefaultLocale = defaultLocale;
-      }
-
     // This will throw NullPointerException if any arguments are null.
-    lookupKey.set(baseName, locale, classLoader);
-
+    lookupKey.set(defaultLocale, baseName, locale, classLoader);
     Object obj = bundleCache.get(lookupKey);
-    ResourceBundle rb = null;
-
     if (obj instanceof ResourceBundle)
-      {
-        return (ResourceBundle) obj;
-      }
-    else if (obj == nullEntry)
-      {
-        // Lookup has failed previously. Fall through.
-      }
-    else
-      {
-	// First, look for a bundle for the specified locale. We don't want
-	// the base bundle this time.
-	boolean wantBase = locale.equals(defaultLocale);
-	ResourceBundle bundle = tryBundle(baseName, locale, classLoader,
-					  wantBase);
-
-        // Try the default locale if neccessary.
-	if (bundle == null && !locale.equals(defaultLocale))
-	  bundle = tryBundle(baseName, defaultLocale, classLoader, true);
+      return (ResourceBundle) obj;

-	BundleKey key = new BundleKey(baseName, locale, classLoader);
-        if (bundle == null)
-	  {
-	    // Cache the fact that this lookup has previously failed.
-	    bundleCache.put(key, nullEntry);
-	  }
-	else
-	  {
-            // Cache the result and return it.
-	    bundleCache.put(key, bundle);
-	    return bundle;
-	  }
-      }
+    if (obj == nullEntry)
+      throw new MissingResourceException("Bundle " + baseName
+                                         + " not found for locale " + locale
+                                         + " by classloader " + classLoader,
+                                         baseName, "");
+    // First, look for a bundle for the specified locale. We don't want
+    // the base bundle this time.
+    boolean wantBase = locale.equals(defaultLocale);
+    ResourceBundle bundle = tryBundle(baseName, locale, classLoader, wantBase);
+    // Try the default locale if neccessary.
+    if (bundle == null && ! wantBase)
+      bundle = tryBundle(baseName, defaultLocale, classLoader, true);

-    throw new MissingResourceException("Bundle " + baseName
-				       + " not found for locale "
-				       + locale
-				       + " by classloader "
-				       + classLoader,
-				       baseName, "");
+    BundleKey key = new BundleKey(defaultLocale, baseName, locale, classLoader);
+    if (bundle == null)
+      {
+        // Cache the fact that this lookup has previously failed.
+        bundleCache.put(key, nullEntry);
+        throw new MissingResourceException("Bundle " + baseName
+                                           + " not found for locale " + locale
+                                           + " by classloader " + classLoader,
+                                           baseName, "");
+      }
+    // Cache the result and return it.
+    bundleCache.put(key, bundle);
+    return bundle;
   }

   /**

Reply via email to