diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 93f5182dbc6..d5fdcdb2686 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -17,6 +17,10 @@ Release 0.23.2 - UNRELEASED HADOOP-8071. Avoid an extra packet in client code when nagling is disabled. (todd) + HADOOP-6502. Improve the performance of Configuration.getClassByName when + the class is not found by caching negative results. + (sharad, todd via todd) + BUG FIXES HADOOP-8042 When copying a file out of HDFS, modifying it, and uploading diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java index 0555a79df6d..c98ff1ece10 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java @@ -1146,6 +1146,22 @@ public class Configuration implements Iterable>, * @throws ClassNotFoundException if the class is not found. */ public Class getClassByName(String name) throws ClassNotFoundException { + Class ret = getClassByNameOrNull(name); + if (ret == null) { + throw new ClassNotFoundException("Class " + name + " not found"); + } + return ret; + } + + /** + * Load a class by name, returning null rather than throwing an exception + * if it couldn't be loaded. This is to avoid the overhead of creating + * an exception. + * + * @param name the class name + * @return the class object, or null if it could not be found. + */ + public Class getClassByNameOrNull(String name) { Map> map; synchronized (CACHE_CLASSES) { @@ -1157,12 +1173,20 @@ public class Configuration implements Iterable>, } } - Class clazz = map.get(name); - if (clazz == null) { - clazz = Class.forName(name, true, classLoader); - if (clazz != null) { - // two putters can race here, but they'll put the same class - map.put(name, clazz); + Class clazz = null; + if (!map.containsKey(name)) { + try { + clazz = Class.forName(name, true, classLoader); + } catch (ClassNotFoundException e) { + map.put(name, null); //cache negative that class is not found + return null; + } + // two putters can race here, but they'll put the same class + map.put(name, clazz); + } else { // check already performed on this class name + clazz = map.get(name); + if (clazz == null) { // found the negative + return null; } } diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java index 0387c7e8b8e..fc5289779e6 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java @@ -86,17 +86,22 @@ public class ReflectionUtils { //invoke configure on theObject try { Class jobConfClass = - conf.getClassByName("org.apache.hadoop.mapred.JobConf"); + conf.getClassByNameOrNull("org.apache.hadoop.mapred.JobConf"); + if (jobConfClass == null) { + return; + } + Class jobConfigurableClass = - conf.getClassByName("org.apache.hadoop.mapred.JobConfigurable"); - if (jobConfClass.isAssignableFrom(conf.getClass()) && + conf.getClassByNameOrNull("org.apache.hadoop.mapred.JobConfigurable"); + if (jobConfigurableClass == null) { + return; + } + if (jobConfClass.isAssignableFrom(conf.getClass()) && jobConfigurableClass.isAssignableFrom(theObject.getClass())) { Method configureMethod = jobConfigurableClass.getMethod("configure", jobConfClass); configureMethod.invoke(theObject, conf); } - } catch (ClassNotFoundException e) { - //JobConf/JobConfigurable not in classpath. no need to configure } catch (Exception e) { throw new RuntimeException("Error in configuring object", e); }