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