HADOOP-8157. Fix race condition in Configuration that could cause spurious ClassNotFoundExceptions after a GC. Contributed by Todd Lipcon.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1303634 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Todd Lipcon 2012-03-22 00:49:06 +00:00
parent 0c4acdc176
commit 76817c28a2
2 changed files with 25 additions and 10 deletions

View File

@ -257,6 +257,9 @@ Release 0.23.3 - UNRELEASED
HADOOP-8191. SshFenceByTcpPort uses netcat incorrectly (todd) HADOOP-8191. SshFenceByTcpPort uses netcat incorrectly (todd)
HADOOP-8157. Fix race condition in Configuration that could cause spurious
ClassNotFoundExceptions after a GC. (todd)
BREAKDOWN OF HADOOP-7454 SUBTASKS BREAKDOWN OF HADOOP-7454 SUBTASKS
HADOOP-7455. HA: Introduce HA Service Protocol Interface. (suresh) HADOOP-7455. HA: Introduce HA Service Protocol Interface. (suresh)

View File

@ -189,6 +189,12 @@ public class Configuration implements Iterable<Map.Entry<String,String>>,
private static final Map<ClassLoader, Map<String, Class<?>>> private static final Map<ClassLoader, Map<String, Class<?>>>
CACHE_CLASSES = new WeakHashMap<ClassLoader, Map<String, Class<?>>>(); CACHE_CLASSES = new WeakHashMap<ClassLoader, Map<String, Class<?>>>();
/**
* Sentinel value to store negative cache results in {@link #CACHE_CLASSES}.
*/
private static final Class<?> NEGATIVE_CACHE_SENTINEL =
NegativeCacheSentinel.class;
/** /**
* Stores the mapping of key to the resource which modifies or loads * Stores the mapping of key to the resource which modifies or loads
* the key most recently * the key most recently
@ -1194,24 +1200,24 @@ public Class<?> getClassByNameOrNull(String name) {
} }
} }
Class<?> clazz = null; Class<?> clazz = map.get(name);
if (!map.containsKey(name)) { if (clazz == null) {
try { try {
clazz = Class.forName(name, true, classLoader); clazz = Class.forName(name, true, classLoader);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
map.put(name, null); //cache negative that class is not found // Leave a marker that the class isn't found
map.put(name, NEGATIVE_CACHE_SENTINEL);
return null; return null;
} }
// two putters can race here, but they'll put the same class // two putters can race here, but they'll put the same class
map.put(name, clazz); map.put(name, clazz);
} else { // check already performed on this class name return clazz;
clazz = map.get(name); } else if (clazz == NEGATIVE_CACHE_SENTINEL) {
if (clazz == null) { // found the negative return null; // not found
return null; } else {
} // cache hit
return clazz;
} }
return clazz;
} }
/** /**
@ -1915,4 +1921,10 @@ private static void addDeprecatedKeys() {
Configuration.addDeprecation("fs.default.name", Configuration.addDeprecation("fs.default.name",
new String[]{CommonConfigurationKeys.FS_DEFAULT_NAME_KEY}); new String[]{CommonConfigurationKeys.FS_DEFAULT_NAME_KEY});
} }
/**
* A unique class which is used as a sentinel value in the caching
* for getClassByName. {@see Configuration#getClassByNameOrNull(String)}
*/
private static abstract class NegativeCacheSentinel {}
} }