hibernate classloading issue
by DANISIK, BAHADIR (BAHADIR)
Hello,
We have an issue in Hibernate ORM 3.6.1 related with the classloading. It is seen in weblogic application server when many concurrent threads are trying to execute hibernate queries.
When a HQL query is executed, first time it is parsed and than cached. Subsequent calls do not have any issues. If too many threads are doing parse operation, because of the single threaded nature of classloading (java6) many threads are waiting the thread doing the parse operation.
An example : "from Device dev where dev.deleted = 0"
When hibernate is executing the query above, it is first parsed. During the parse operation hibernate is checking the alias name "dev" as a class. A class load operation is executed. It will not find a class named "dev", but for some reason it is doing a lookup. The package name of "Device" class like "com.mycompany.domain" is also looked up as a class by doing class load operation. If there are many (400+) concurrent threads, doing same hibernate call, they are stuck in the parsing because of single threaded class loading.
This behavior is causing long warm up time in the application server when there is a burs t of traffic.
As an improvement, I am planning to add a negative cache for the non existing classes to prevent going to the class loader again and again.
Here is the modification in ReflectHelper.java: (Changes are in red)
private static Map<String, Boolean> hmNonExistingClasses = new ConcurrentHashMap<String, Boolean>();
/**
* Perform resolution of a class name.
* <p/>
* Same as {@link #classForName(String, Class)} except that here we delegate to
* {@link Class#forName(String)} if the context classloader lookup is unsuccessful.
*
* @param name The class name
* @return The class reference.
* @throws ClassNotFoundException From {@link Class#forName(String)}.
*/
public static Class classForName(String name) throws ClassNotFoundException {
if (hmNonExistingClasses.containsKey(name))
throw new ClassNotFoundException(name);
try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if ( contextClassLoader != null ) {
return contextClassLoader.loadClass(name);
}
}
catch ( Throwable ignore ) {
}
try {
return Class.forName( name );
} catch (ClassNotFoundException cnfe) {
hmNonExistingClasses.put(name, true);
throw cnfe;
}
}
Can you please also let me know if I can make this change in hibernate 3.6.1 (in a new branc)without making our product open source? My understanding is, I need to make this change public. I have created a new branch locally in git and want to push the changes to a new branch named "3.6.1.Final_ALU" in github. Can you please let me know if I can create the new branch?
Thanks for your help,
Bahadir DANISIK.