8076287: Performance degradation observed with TimeZone Benchmark
Reviewed-by: okutsu
This commit is contained in:
parent
41b53b0d3c
commit
5b2c289414
@ -47,6 +47,7 @@ import java.util.Calendar;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -250,17 +251,17 @@ public class LocaleResources {
|
||||
return (String) localeName;
|
||||
}
|
||||
|
||||
String[] getTimeZoneNames(String key, int size) {
|
||||
String[] getTimeZoneNames(String key) {
|
||||
String[] names = null;
|
||||
String cacheKey = TIME_ZONE_NAMES + size + '.' + key;
|
||||
String cacheKey = TIME_ZONE_NAMES + '.' + key;
|
||||
|
||||
removeEmptyReferences();
|
||||
ResourceReference data = cache.get(cacheKey);
|
||||
|
||||
if (data == null || ((names = (String[]) data.get()) == null)) {
|
||||
if (Objects.isNull(data) || Objects.isNull((names = (String[]) data.get()))) {
|
||||
TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
|
||||
if (tznb.containsKey(key)) {
|
||||
names = tznb.getStringArray(key, size);
|
||||
names = tznb.getStringArray(key);
|
||||
cache.put(cacheKey,
|
||||
new ResourceReference(cacheKey, (Object) names, referenceQueue));
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package sun.util.locale.provider;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.spi.TimeZoneNameProvider;
|
||||
@ -95,8 +96,9 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider {
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName(String id, boolean daylight, int style, Locale locale) {
|
||||
String[] names = getDisplayNameArray(id, 5, locale);
|
||||
if (names != null) {
|
||||
String[] names = getDisplayNameArray(id, locale);
|
||||
if (Objects.nonNull(names)) {
|
||||
assert names.length >= 7;
|
||||
int index = daylight ? 3 : 1;
|
||||
if (style == TimeZone.SHORT) {
|
||||
index++;
|
||||
@ -108,18 +110,18 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider {
|
||||
|
||||
@Override
|
||||
public String getGenericDisplayName(String id, int style, Locale locale) {
|
||||
String[] names = getDisplayNameArray(id, 7, locale);
|
||||
if (names != null && names.length >= 7) {
|
||||
String[] names = getDisplayNameArray(id, locale);
|
||||
if (Objects.nonNull(names)) {
|
||||
assert names.length >= 7;
|
||||
return names[(style == TimeZone.LONG) ? 5 : 6];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] getDisplayNameArray(String id, int n, Locale locale) {
|
||||
if (id == null || locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id, n);
|
||||
private String[] getDisplayNameArray(String id, Locale locale) {
|
||||
Objects.requireNonNull(id);
|
||||
Objects.requireNonNull(locale);
|
||||
return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.spi.TimeZoneNameProvider;
|
||||
@ -100,9 +101,9 @@ public final class TimeZoneNameUtility {
|
||||
* Retrieve display names for a time zone ID.
|
||||
*/
|
||||
public static String[] retrieveDisplayNames(String id, Locale locale) {
|
||||
if (id == null || locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
Objects.requireNonNull(id);
|
||||
Objects.requireNonNull(locale);
|
||||
|
||||
return retrieveDisplayNamesImpl(id, locale);
|
||||
}
|
||||
|
||||
@ -115,9 +116,12 @@ public final class TimeZoneNameUtility {
|
||||
* @return the requested generic time zone display name, or null if not found.
|
||||
*/
|
||||
public static String retrieveGenericDisplayName(String id, int style, Locale locale) {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
|
||||
return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, "generic", style, id);
|
||||
String[] names = retrieveDisplayNamesImpl(id, locale);
|
||||
if (Objects.nonNull(names)) {
|
||||
return names[6 - style];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,140 +134,53 @@ public final class TimeZoneNameUtility {
|
||||
* @return the requested time zone name, or null if not found.
|
||||
*/
|
||||
public static String retrieveDisplayName(String id, boolean daylight, int style, Locale locale) {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
|
||||
return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, daylight ? "dst" : "std", style, id);
|
||||
String[] names = retrieveDisplayNamesImpl(id, locale);
|
||||
if (Objects.nonNull(names)) {
|
||||
return names[(daylight ? 4 : 2) - style];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] retrieveDisplayNamesImpl(String id, Locale locale) {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
|
||||
String[] names;
|
||||
Map<Locale, String[]> perLocale = null;
|
||||
|
||||
SoftReference<Map<Locale, String[]>> ref = cachedDisplayNames.get(id);
|
||||
if (ref != null) {
|
||||
Map<Locale, String[]> perLocale = ref.get();
|
||||
if (perLocale != null) {
|
||||
String[] names = perLocale.get(locale);
|
||||
if (names != null) {
|
||||
if (Objects.nonNull(ref)) {
|
||||
perLocale = ref.get();
|
||||
if (Objects.nonNull(perLocale)) {
|
||||
names = perLocale.get(locale);
|
||||
if (Objects.nonNull(names)) {
|
||||
return names;
|
||||
}
|
||||
names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id);
|
||||
if (names != null) {
|
||||
perLocale.put(locale, names);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
String[] names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id);
|
||||
if (names != null) {
|
||||
Map<Locale, String[]> perLocale = new ConcurrentHashMap<>();
|
||||
perLocale.put(locale, names);
|
||||
ref = new SoftReference<>(perLocale);
|
||||
cachedDisplayNames.put(id, ref);
|
||||
// build names array
|
||||
names = new String[7];
|
||||
names[0] = id;
|
||||
for (int i = 1; i <= 6; i ++) {
|
||||
names[i] = pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale,
|
||||
i<5 ? (i<3 ? "std" : "dst") : "generic", i%2, id);
|
||||
}
|
||||
|
||||
if (Objects.isNull(perLocale)) {
|
||||
perLocale = new ConcurrentHashMap<>();
|
||||
}
|
||||
perLocale.put(locale, names);
|
||||
ref = new SoftReference<>(perLocale);
|
||||
cachedDisplayNames.put(id, ref);
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a localized time zone strings from a TimeZoneNameProvider
|
||||
* implementation.
|
||||
*/
|
||||
private static class TimeZoneNameArrayGetter
|
||||
implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider,
|
||||
String[]>{
|
||||
private static final TimeZoneNameArrayGetter INSTANCE =
|
||||
new TimeZoneNameArrayGetter();
|
||||
|
||||
@Override
|
||||
public String[] getObject(TimeZoneNameProvider timeZoneNameProvider,
|
||||
Locale locale,
|
||||
String requestID,
|
||||
Object... params) {
|
||||
assert params.length == 0;
|
||||
|
||||
// First, try to get names with the request ID
|
||||
String[] names = buildZoneStrings(timeZoneNameProvider, locale, requestID);
|
||||
|
||||
if (names == null) {
|
||||
Map<String, String> aliases = ZoneInfo.getAliasTable();
|
||||
|
||||
if (aliases != null) {
|
||||
// Check whether this id is an alias, if so,
|
||||
// look for the standard id.
|
||||
String canonicalID = aliases.get(requestID);
|
||||
if (canonicalID != null) {
|
||||
names = buildZoneStrings(timeZoneNameProvider, locale, canonicalID);
|
||||
}
|
||||
if (names == null) {
|
||||
// There may be a case that a standard id has become an
|
||||
// alias. so, check the aliases backward.
|
||||
names = examineAliases(timeZoneNameProvider, locale,
|
||||
canonicalID == null ? requestID : canonicalID, aliases);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (names != null) {
|
||||
names[0] = requestID;
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String[] examineAliases(TimeZoneNameProvider tznp, Locale locale,
|
||||
String id,
|
||||
Map<String, String> aliases) {
|
||||
if (aliases.containsValue(id)) {
|
||||
for (Map.Entry<String, String> entry : aliases.entrySet()) {
|
||||
if (entry.getValue().equals(id)) {
|
||||
String alias = entry.getKey();
|
||||
String[] names = buildZoneStrings(tznp, locale, alias);
|
||||
if (names != null) {
|
||||
return names;
|
||||
}
|
||||
names = examineAliases(tznp, locale, alias, aliases);
|
||||
if (names != null) {
|
||||
return names;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String[] buildZoneStrings(TimeZoneNameProvider tznp,
|
||||
Locale locale, String id) {
|
||||
String[] names = new String[5];
|
||||
|
||||
for (int i = 1; i <= 4; i ++) {
|
||||
names[i] = tznp.getDisplayName(id, i>=3, i%2, locale);
|
||||
|
||||
if (names[i] == null) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
// this id seems not localized by this provider
|
||||
return null;
|
||||
case 2:
|
||||
case 4:
|
||||
// If the display name for SHORT is not supplied,
|
||||
// copy the LONG name.
|
||||
names[i] = names[i-1];
|
||||
break;
|
||||
case 3:
|
||||
// If the display name for DST is not supplied,
|
||||
// copy the "standard" name.
|
||||
names[3] = names[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TimeZoneNameGetter
|
||||
implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider,
|
||||
String> {
|
||||
@ -299,18 +216,16 @@ public final class TimeZoneNameUtility {
|
||||
private static String examineAliases(TimeZoneNameProvider tznp, Locale locale,
|
||||
String requestID, String tzid, int style,
|
||||
Map<String, String> aliases) {
|
||||
if (aliases.containsValue(tzid)) {
|
||||
for (Map.Entry<String, String> entry : aliases.entrySet()) {
|
||||
if (entry.getValue().equals(tzid)) {
|
||||
String alias = entry.getKey();
|
||||
String name = getName(tznp, locale, requestID, style, alias);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
name = examineAliases(tznp, locale, requestID, alias, style, aliases);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
for (Map.Entry<String, String> entry : aliases.entrySet()) {
|
||||
if (entry.getValue().equals(tzid)) {
|
||||
String alias = entry.getKey();
|
||||
String name = getName(tznp, locale, requestID, style, alias);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
name = examineAliases(tznp, locale, requestID, alias, style, aliases);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -60,26 +61,6 @@ import java.util.Set;
|
||||
*/
|
||||
public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
|
||||
|
||||
/**
|
||||
* Returns a String array containing time zone names. The String array has
|
||||
* at most size elements.
|
||||
*
|
||||
* @param key the time zone ID for which names are obtained
|
||||
* @param size the requested size of array for names
|
||||
* @return a String array containing names
|
||||
*/
|
||||
public String[] getStringArray(String key, int size) {
|
||||
String[] names = handleGetObject(key, size);
|
||||
if ((names == null || names.length != size) && parent != null) {
|
||||
names = ((TimeZoneNamesBundle)parent).getStringArray(key, size);
|
||||
}
|
||||
if (names == null) {
|
||||
throw new MissingResourceException("no time zone names", getClass().getName(), key);
|
||||
}
|
||||
return names;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps time zone IDs to locale-specific names.
|
||||
* The value returned is an array of five strings:
|
||||
@ -89,6 +70,8 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
|
||||
* <li>The short name of the time zone in standard time (localized).
|
||||
* <li>The long name of the time zone in daylight savings time (localized).
|
||||
* <li>The short name of the time zone in daylight savings time (localized).
|
||||
* <li>The long name of the time zone in generic form (localized).
|
||||
* <li>The short name of the time zone in generic form (localized).
|
||||
* </ul>
|
||||
* The localized names come from the subclasses's
|
||||
* <code>getContents</code> implementations, while the time zone
|
||||
@ -96,16 +79,12 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
|
||||
*/
|
||||
@Override
|
||||
public Object handleGetObject(String key) {
|
||||
return handleGetObject(key, 5);
|
||||
}
|
||||
|
||||
private String[] handleGetObject(String key, int n) {
|
||||
String[] contents = (String[]) super.handleGetObject(key);
|
||||
if (contents == null) {
|
||||
if (Objects.isNull(contents)) {
|
||||
return null;
|
||||
}
|
||||
int clen = Math.min(n - 1, contents.length);
|
||||
String[] tmpobj = new String[clen+1];
|
||||
int clen = contents.length;
|
||||
String[] tmpobj = new String[7];
|
||||
tmpobj[0] = key;
|
||||
System.arraycopy(contents, 0, tmpobj, 1, clen);
|
||||
return tmpobj;
|
||||
|
@ -47,7 +47,8 @@ public final class TimeZoneNames_en_IE extends TimeZoneNamesBundle {
|
||||
protected final Object[][] getContents() {
|
||||
return new Object[][] {
|
||||
{"Europe/London", new String[] {"Greenwich Mean Time", "GMT",
|
||||
"Irish Summer Time", "IST" /*Dublin*/}},
|
||||
"Irish Summer Time", "IST", /*Dublin*/
|
||||
"Irish Time", "IT" /*Dublin*/}},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
import java.text.*;
|
||||
import java.time.format.TextStyle;
|
||||
import java.util.*;
|
||||
import sun.util.locale.provider.*;
|
||||
import sun.util.resources.*;
|
||||
@ -42,6 +43,7 @@ public class TimeZoneNameProviderTest extends ProviderTest {
|
||||
test2();
|
||||
test3();
|
||||
aliasTest();
|
||||
genericFallbackTest();
|
||||
}
|
||||
|
||||
void test1() {
|
||||
@ -169,9 +171,9 @@ public class TimeZoneNameProviderTest extends ProviderTest {
|
||||
for (int style : new int[] { TimeZone.LONG, TimeZone.SHORT }) {
|
||||
String osakaStd = tz.getDisplayName(false, style, OSAKA);
|
||||
if (osakaStd != null) {
|
||||
// No API for getting generic time zone names
|
||||
String generic = TimeZoneNameUtility.retrieveGenericDisplayName(tzname,
|
||||
style, GENERIC);
|
||||
String generic = tz.toZoneId().getDisplayName(
|
||||
style == TimeZone.LONG ? TextStyle.FULL : TextStyle.SHORT,
|
||||
GENERIC);
|
||||
String expected = "Generic " + osakaStd;
|
||||
if (!expected.equals(generic)) {
|
||||
throw new RuntimeException("Wrong generic name: got=\"" + generic
|
||||
@ -230,4 +232,20 @@ public class TimeZoneNameProviderTest extends ProviderTest {
|
||||
throw new RuntimeException("Provider's localized name is not available for an alias ID: "+JAPAN+". result: "+japan+" expected: "+JST_IN_OSAKA);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests whether generic names can be retrieved through fallback.
|
||||
* The test assumes the provider impl for OSAKA locale does NOT
|
||||
* provide generic names.
|
||||
*/
|
||||
final String PT = "PT"; // SHORT generic name for "America/Los_Angeles"
|
||||
void genericFallbackTest() {
|
||||
String generic =
|
||||
TimeZone.getTimeZone(LATIME)
|
||||
.toZoneId()
|
||||
.getDisplayName(TextStyle.SHORT, OSAKA);
|
||||
if (!PT.equals(generic)) {
|
||||
throw new RuntimeException("Generic name fallback failed. got: "+generic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user